【BZOJ 2039】 2039: [2009国家集训队]employ人员雇佣 (最小割)
2039: [2009国家集训队]employ人员雇佣
Time Limit: 20 Sec Memory Limit: 259 MB
Submit: 1511 Solved: 728Description
作为一个富有经营头脑的富翁,小L决定从本国最优秀的经理中雇佣一些来经营自己的公司。这些经理相互之间合作有一个贡献指数,(我们用Ei,j表示i经理对j经理的了解程度),即当经理i和经理j同时被雇佣时,经理i会对经理j做出贡献,使得所赚得的利润增加Ei,j。当然,雇佣每一个经理都需要花费一定的金钱Ai,对于一些经理可能他做出的贡献不值得他的花费,那么作为一个聪明的人,小L当然不会雇佣他。 然而,那些没有被雇佣的人会被竞争对手所雇佣,这个时候那些人会对你雇佣的经理的工作造成影响,使得所赚得的利润减少Ei,j(注意:这里的Ei,j与上面的Ei,j 是同一个)。 作为一个效率优先的人,小L想雇佣一些人使得净利润最大。你可以帮助小L解决这个问题吗?
Input
第一行有一个整数N<=1000表示经理的个数 第二行有N个整数Ai表示雇佣每个经理需要花费的金钱 接下来的N行中一行包含N个数,表示Ei,j,即经理i对经理j的了解程度。(输入满足Ei,j=Ej,i)
Output
第一行包含一个整数,即所求出的最大值。
Sample Input
3
3 5 100
0 6 1
6 0 2
1 2 0
Sample Output
1
【数据规模和约定】
20%的数据中N<=10
50%的数据中N<=100
100%的数据中 N<=1000, Ei,j<=maxlongint, Ai<=maxlongint
HINT
Source
【分析】
海陆型构图。//到时候再总结这个吧
S集表示雇佣,T集表示不雇佣。每个经理拆成x,y两点。s向所有x点连,流量为雇佣费用。对于每个Ei,j,i,j经理连一条流量为2*Ei,j的无向边,同时i和j都向t连流量为Ei,j的边,最小割为所有Ei,j*2减最大流。由于边数大,需要合并一下边。
【啊一开始构错图了,好桑心。。。。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 #include<queue> 7 using namespace std; 8 #define Maxn 1100 9 #define INF 0xfffffff 10 11 int mymin(int x,int y) {return x<y?x:y;} 12 13 int a[Maxn],w[Maxn][Maxn]; 14 15 struct node 16 { 17 int x,y,f,next,o; 18 }t[Maxn*Maxn*10]; 19 int len,first[Maxn]; 20 21 void ins(int x,int y,int f) 22 { 23 t[++len].x=x;t[len].y=y;t[len].f=f; 24 t[len].next=first[x];first[x]=len;t[len].o=len+1; 25 t[++len].x=y;t[len].y=x;t[len].f=0; 26 t[len].next=first[y];first[y]=len;t[len].o=len-1; 27 } 28 29 int st,ed; 30 int dis[Maxn]; 31 queue<int > q; 32 bool bfs() 33 { 34 for(int i=1;i<=ed;i++) dis[i]=-1; 35 while(!q.empty()) q.pop(); 36 dis[st]=0;q.push(st); 37 while(!q.empty()) 38 { 39 int x=q.front(); 40 for(int i=first[x];i;i=t[i].next) if(t[i].f>0) 41 { 42 int y=t[i].y; 43 if(dis[y]==-1) 44 { 45 dis[y]=dis[x]+1; 46 q.push(y); 47 } 48 } 49 q.pop(); 50 } 51 if(dis[ed]==-1) return 0; 52 return 1; 53 } 54 55 int ffind(int x,int flow) 56 { 57 if(x==ed) return flow; 58 int now=0; 59 for(int i=first[x];i;i=t[i].next) if(t[i].f>0) 60 { 61 int y=t[i].y; 62 if(dis[y]==dis[x]+1) 63 { 64 int a=ffind(y,mymin(flow-now,t[i].f)); 65 t[i].f-=a; 66 t[t[i].o].f+=a; 67 now+=a; 68 } 69 if(now==flow) break; 70 } 71 if(now==0) dis[x]=-1; 72 return now; 73 } 74 75 void output() 76 { 77 for(int i=1;i<=len;i+=2) 78 { 79 printf("%d -> %d %d\n",t[i].x,t[i].y,t[i].f); 80 }printf("\n"); 81 } 82 83 int ans; 84 void max_flow() 85 { 86 while(bfs()) 87 { 88 ans-=ffind(st,INF); 89 // output(); 90 // while(1); 91 } 92 } 93 94 int s[Maxn]; 95 96 int main() 97 { 98 int n; 99 scanf("%d",&n); 100 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 101 ans=0; 102 for(int i=1;i<=n;i++) 103 { 104 s[i]=0; 105 for(int j=1;j<=n;j++) 106 { 107 scanf("%d",&w[i][j]); 108 s[i]+=w[i][j]; 109 ans+=w[i][j]; 110 } 111 } 112 113 len=0; 114 memset(first,0,sizeof(first)); 115 st=n+1;ed=st+1; 116 for(int i=1;i<=n;i++) ins(st,i,a[i]); 117 for(int i=1;i<=n;i++) 118 for(int j=i+1;j<=n;j++) {ins(i,j,2*w[i][j]);ins(j,i,2*w[i][j]);} 119 for(int i=1;i<=n;i++) ins(i,ed,s[i]); 120 // output(); 121 max_flow(); 122 printf("%d\n",ans); 123 return 0; 124 }
2017-03-28 20:58:42