BZOJ2039_employ人员雇佣_KEY
网络流,求最小割。
设tot为所有盈利的和,即所有人(不花钱)雇佣。
对于S->i建一条容量为c[i]的边,i->j建一条S[i][j]*2的边,之所以这样建是因为如果不选这个人还会亏S[i][j]。
对于i->T建一条容量为∑S[i][j]的边。
最小割=最大流,跑Dinic
code:
/************************************************************** Problem: 2039 User: yekehe Language: C++ Result: Accepted Time:4428 ms Memory:52316 kb ****************************************************************/ #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; int read() { char c;while(c=getchar(),c<'0'||c>'9'); int x=c-'0';while(c=getchar(),c>='0'&&c<='9')x=x*10+c-'0'; return x; } int N,a[1005],MP[1005][1005]; int head[1005],nxt[10040005],To[1004005],W[1004005],cnt; void add(int x,int y,int c) { To[cnt]=y,W[cnt]=c; nxt[cnt]=head[x]; head[x]=cnt; cnt++; } int dist[1005],l[1005],h,t; int BFS() { h=t=0; memset(dist,0xfff,sizeof dist); l[++t]=0,dist[0]=1; while(h<t){ int front=l[++h]; for(int i=head[front];i!=-1;i=nxt[i]){ if(dist[To[i]]==-1 && W[i]){ dist[To[i]]=dist[front]+1; l[++t]=To[i]; } } } return dist[N+1]!=-1; } int DFS(int x,int w) { if(x==N+1 || !w)return w; int res=0; for(int i=head[x];i!=-1&&w;i=nxt[i]){ if(dist[x]+1==dist[To[i]] && W[i]){ int DK=DFS(To[i],min(w,W[i])); res+=DK;w-=DK; W[i]-=DK,W[i^1]+=DK; } } if(!res)dist[x]=-1; return res; } int tot=0; void Dinic() { int ans=0; while(BFS()) ans+=DFS(0,2e9); printf("%d",tot-ans); return ; } int main() { memset(head,-1,sizeof head); memset(nxt,-1,sizeof nxt); N=read(); register int i,j; for(i=1;i<=N;i++) a[i]=read(),add(0,i,a[i]),add(i,0,0); for(i=1;i<=N;i++) for(j=1;j<=N;j++) MP[i][j]=read(),tot+=MP[i][j]; for(i=1;i<=N;i++) for(j=i+1;j<=N;j++) add(i,j,MP[i][j]<<1),add(j,i,MP[i][j]<<1); for(i=1;i<=N;i++){ int res=0;for(j=1;j<=N;j++)res+=MP[i][j]; add(i,N+1,res),add(N+1,i,0); } Dinic(); return 0; }