蛋糕分发 - summer camp

题目描述:

恬恬的生日临近了。宇扬给她准备了一个 蛋糕。

正如往常一样,宇扬在蛋糕上插了nnn支蜡烛,并把蛋糕分为mmm个区域。因为某种原因,他必须把第iii根蜡烛插在第aia\_iai个区域或第bib\_ibi个区域。区域之间是不相交的。宇扬在一个区域内同时摆放xxx支蜡烛就要花费x2x^2x2的时间。宇扬布置蛋糕所用的总时间是他在每个区域花的时间的和。

宇扬想快些见到恬恬,你能告诉他布置蛋糕最少需要多少时间吗?

输入:

第一行包含两个整数nnn,mmm(1≤n≤501 \le n \le 501n50, 2≤m≤502\le m\le 502m50)。

接下来nnn行,每行两个整数ai,bia\_i,b\_iai,bi1≤ai,bi≤m1 \le a\_i, b\_i \le m1ai,bim)。

输出:

一个整数表示答案。

样例输入
3 3
1 2
1 2
1 2
样例输出
5
描述

题目描述:

恬恬的生日临近了。宇扬给她准备了一个 蛋糕。

正如往常一样,宇扬在蛋糕上插了nnn支蜡烛,并把蛋糕分为mmm个区域。因为某种原因,他必须把第iii根蜡烛插在第aia\_iai个区域或第bib\_ibi个区域。区域之间是不相交的。宇扬在一个区域内同时摆放xxx支蜡烛就要花费x2x^2x2的时间。宇扬布置蛋糕所用的总时间是他在每个区域花的时间的和。

宇扬想快些见到恬恬,你能告诉他布置蛋糕最少需要多少时间吗?

输入:

第一行包含两个整数nnn,mmm(1≤n≤501 \le n \le 501n50, 2≤m≤502\le m\le 502m50)。

接下来nnn行,每行两个整数ai,bia\_i,b\_iai,bi1≤ai,bi≤m1 \le a\_i, b\_i \le m1ai,bim)。

输出:

一个整数表示答案。

题意 :

  给你 n 根蜡烛,同时告诉你每根蜡烛可以插在哪个区域中,对于同一个区域内插入的蜡烛总的花费为此区域内蜡烛数量的平方,问最小的花费是多少

思路分析 :

  贪心对于此问题是不正确的,考虑一下网络流建图

  考虑费用流时把每个part拆成n个点,选择第i个点的代表为放置i块蛋糕和(i - 1)块蛋糕的时间差,这个时间差是递增的,因此在费用流的过程中必定会从小到大选择
具体建图:左边n个点代表n个蛋糕,右边m * n个点代表m个part,每个part拆成n个点。源点向每个左边的点连一条流量1费用0的边,每个右边的点向汇点连一条流量1费用0的编。每个蛋糕向可以放的两个part的所有点连边,连向第i个点的费用为i^2 - (i - 1)^2,流量为1。这样求最小费用流既为答案。

代码示例 :

#include <bits/stdc++.h>
using namespace std;

const int maxn = 1e4;
const int maxm = 1e5;
const int inf = 0x3f3f3f3f;
struct Edge
{
    int to,next,flow,cost; // flow 表示水现有的流量
}edge[maxm];
int head[maxn],tol;
int pre[maxn],dis[maxn];
bool vis[maxn];
int N; //节点个数,编号0->N-1 !全局变量 需要init赋值或主函数改变

void init(int n)
{
    N=n;
    tol = 0;
    memset(head,-1,sizeof(head));
}

void addedge(int u,int v,int cap,int cost) //边起点,终点,流量,费用
{
    edge[tol].to = v;
    edge[tol].cost = cost;
    edge[tol].flow = cap;
    edge[tol].next = head[u];
    head[u] = tol++;
    edge[tol].to = u;
    edge[tol].cost = -cost;
    edge[tol].flow = 0;
    edge[tol].next = head[v];
    head[v] = tol++;
}

bool spfa(int s,int t)     //单源最短路径算法 可判断负环
{
    queue<int >q;
    for(int i=0;i<N;i++)
    {
        dis[i] = inf;
        vis[i] = false;
        pre[i] = -1;
    }
    dis[s] = 0;
    vis[s] = true;
    q.push(s);
    while(!q.empty())
    {
        int u = q.front();
        q.pop();
        vis[u] = false;
        for(int i=head[u];i!=-1;i=edge[i].next)
        {
            int v= edge[i].to;
            if(edge[i].flow && dis[v]>dis[u]+edge[i].cost)
            {
                dis[v] = dis[u] + edge[i].cost;
                pre[v] = i;
                if(!vis[v])
                {
                    vis[v] = true;
                    q.push(v);
                }
            }
        }
    }
    if(pre[t]==-1) return false;
    else return true;
}

int MCMF(int s,int t,int &cost)  //MinCostMaxFlow  返回最大流,cost存最小费用
{
    int flow = 0;
    cost = 0;
    while(spfa(s,t))
    {
        int Min = inf;
        for(int i= pre[t];i!=-1;i=pre[edge[i^1].to])
        {
            if(Min>edge[i].flow)
                Min=edge[i].flow;
        }
        for(int i= pre[t];i!=-1;i=pre[edge[i^1].to])
        {
            edge[i].flow -= Min;
            edge[i^1].flow +=Min;
            cost += edge[i].cost*Min;
        }
        flow += Min;
    }
    //printf("++++ %d  %d \n", flow, tol);
    return flow;
}

int n, m;

int main() {
    int a, b;
    cin >> n >> m;
    init(n+m+2); 
    for(int i = 1; i <= n; i++){
        scanf("%d%d", &a, &b);
        addedge(0, i, 1, 0);
        addedge(i, n+a, 1, 0);
        addedge(i, n+b, 1, 0);    
    }
    for(int i = n+1; i <= n+m; i++){
        for(int j = 1; j <= 99; j += 2){
            addedge(i, n+m+1, 1, j);
        }
    } 
    int ans;
    MCMF(0, n+m+1, ans);
    printf("%d\n", ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/ccut-ry/p/9434398.html