spoj (BOXS IT)371(最小费用最大流)

来源:互联网 发布:彩虹六号数据统计 编辑:程序博客网 时间:2024/05/17 07:47

题目链接:http://www.spoj.pl/status/

题意描述:有n个盒子排成一个圈,每个盒子开始有x个球,且所有盒子中球的总和不超过n,现在移动盒子中的球使得每个盒子最多有1个球,移动只能在相邻的盒子之间进行,求最少要移动多少次满足要求(每个盒子最多只能有一个球)


分析: 最小费用最大流题目,建图: 源点到每个盒子连边,容量为盒子中求的个数,费用为0,每个盒子向汇点连边,容量为1,费用为0,相邻的盒子之间连边容量为无穷大,费用为1,求最小费用最大流即为结果


代码:

#include<iostream>#include<cstdio>#include<cstring>using namespace std;const int inf = 0x3fffffff;const int N = 1010;const int E = 20000;struct node{int y, nxt,cost,w;}edge[E];int head[N],e;int dist[N],pre[N],vis[N],que[N];void addedge(int x,int y, int w, int cost ){edge[e].y = y;edge[e].w = w;edge[e].cost = cost;edge[e].nxt = head[x];head[x]=e++;edge[e].y = x;edge[e].w = 0;edge[e].cost = -cost;edge[e].nxt = head[y];head[y] = e++;}int minCmaxF(int s ,int t){int c=0,  f,r,min,p,i;int u, v;while(1){for( i=s;i<=t;i++){dist[i]=inf;vis[i]=false;}que[0]=s;vis[s]=true;dist[s]=0; f = 0;r = 1;while(f!=r){ u = que[f]; f = (f+1)%N;for(i=head[u];i!=-1;i=edge[i].nxt){ v = edge[i].y;if(edge[i].w>0&&dist[v]>dist[u]+edge[i].cost){dist[v]=dist[u]+edge[i].cost;pre[v]=i;if(vis[v]==false){vis[v]=true;que[r]=v;r = (r+1)%N;}}}vis[u]=false;}if(dist[t]==inf)break;        min = inf;        for(u=t;u!=s;u=edge[pre[u]^1].y){p = pre[u];if(min > edge[p].w)min = edge[p].w;}for(u=t;u!=s;u=edge[pre[u]^1].y){p=pre[u];edge[p].w -= min;edge[p^1].w+=min;c += edge[p].cost*min;}} return c;}int main (){int t;int n, i,c;scanf("%d",&t);while (t--){scanf("%d",&n);memset(head,-1,sizeof(head));e = 0;for(i=1;i<=n;i++){scanf("%d",&c);addedge(0,i,c,0);addedge(i,n+1,1,0);}for(i=1;i<n;i++){addedge(i,i+1,inf,1);addedge(i+1,i,inf,1);}addedge(n,1,inf,1);addedge(1,n,inf,1);        int x = minCmaxF(0,n+1);printf("%d\n",x);}return 0;}