BZOJ 2039 2009国家集训队 employ人员雇佣 最小割

来源:互联网 发布:温州淘宝城在哪里 编辑:程序博客网 时间:2024/05/17 18:41

题目大意:给定n个人,每个人有一个佣金,i和j如果同时被雇佣会产生2*E(i,j)的效益,i和j如果一个被雇佣一个不被雇佣会产生E(i,j)的亏损,求最大收益

首先对于每一个cost[i],从点i出发向汇点连一条流量为cost[i]的边

对于每一对点(i,j),建图如下:

从S向点i和点j各连一条流量为E(i,j)的边

i和j之间连一条流量为2*E(i,j)的双向边

这样可以保证每种割法对应一种雇佣方案

用矩阵上数字的总和减掉最小割即是答案

边集会很大,因此合并后再加即可

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define M 1010#define S 0#define T (n+1)#define INF 0x3f3f3f3f3f3f3f3fllusing namespace std;struct abcd{int to,next;long long f;}table[10010010];int head[M],tot=1;int n;long long ans,a[M];void Add(int x,int y,long long z){table[++tot].to=y;table[tot].f=z;table[tot].next=head[x];head[x]=tot;}void Link(int x,int y,long long z){Add(x,y,z);Add(y,x,z);}namespace Max_Flow{int dpt[M];bool BFS(){static int q[M];int i,r=0,h=0;memset(dpt,-1,sizeof dpt);q[++r]=S;dpt[S]=1;while(r!=h){int x=q[++h];for(i=head[x];i;i=table[i].next)if(table[i].f&&!~dpt[table[i].to]){dpt[table[i].to]=dpt[x]+1;q[++r]=table[i].to;if(table[i].to==T)return true;}}return false;}long long Dinic(int x,long long flow){int i;long long left=flow;if(x==T) return flow;for(i=head[x];i&&left;i=table[i].next)if(table[i].f&&dpt[table[i].to]==dpt[x]+1){long long temp=Dinic(table[i].to,min(left,table[i].f) );left-=temp;table[i].f-=temp;table[i^1].f+=temp;}if(left) dpt[x]=-1;return flow-left;}}int main(){int i,j,x;cin>>n;for(i=1;i<=n;i++){scanf("%d",&x);Link(i,T,x);}for(i=1;i<=n;i++)for(j=1;j<=n;j++){scanf("%d",&x);ans+=x;if(i>=j) continue;a[i]+=x;a[j]+=x;Link(i,j,(long long)x<<1);}for(i=1;i<=n;i++)Link(S,i,a[i]);using namespace Max_Flow;while( BFS() )ans-=Dinic(S,INF);cout<<ans<<endl;return 0;}


1 0
原创粉丝点击