[bzoj3894]文理分科
假设没有同时选文理科的收益,可以先将所有点的文理科收益都加起来,考虑最少要删掉多少收益,源点连向每一个点文科的收益,每一个点向汇点流理科的收益,然后每一条路径都最小割,即去掉了较小的收益。
但还有同时选同一种科目的收益,同样先加上所有选同种科目的收益,然后对于点(i,j),新增k1和k2两个点,源点向k1流都选文科的边,k1向五个点、五个点向k2都连inf的边,k2向汇点流都选理科的边。同样跑最小割,考虑当这五个点全部都删去文理科,那么只需要再删掉这个点的都选文理科即可,当这个五个点选择删去的不同时,一定要两个都删掉才能满足,因此就是最小割。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 30005 4 #define id (i-1)*m+j 5 #define inf 0x3f3f3f3f 6 struct ji{ 7 int nex,to,len; 8 }edge[N*10]; 9 queue<int>q; 10 int E,n,m,k,ans,d[N],head[N],work[N]; 11 void add(int x,int y,int z){ 12 edge[E].nex=head[x]; 13 edge[E].to=y; 14 edge[E].len=z; 15 head[x]=E++; 16 if (E&1)add(y,x,0); 17 } 18 bool bfs(){ 19 q.push(0); 20 memset(d,-1,sizeof(d)); 21 d[0]=0; 22 while (!q.empty()){ 23 int k=q.front(); 24 q.pop(); 25 for(int i=head[k];i!=-1;i=edge[i].nex) 26 if ((edge[i].len)&&(d[edge[i].to]<0)){ 27 d[edge[i].to]=d[k]+1; 28 q.push(edge[i].to); 29 } 30 } 31 return d[n]>=0; 32 } 33 int dfs(int k,int s){ 34 if (k==n)return s; 35 int p; 36 for(int &i=work[k];i!=-1;i=edge[i].nex) 37 if ((edge[i].len)&&(d[edge[i].to]==d[k]+1)){ 38 p=dfs(edge[i].to,min(s,edge[i].len)); 39 if (p){ 40 edge[i].len-=p; 41 edge[i^1].len+=p; 42 return p; 43 } 44 } 45 return 0; 46 } 47 int dinic(){ 48 int k,ans=0; 49 while (bfs()){ 50 memcpy(work,head,sizeof(work)); 51 while (k=dfs(0,inf))ans+=k; 52 } 53 return ans; 54 } 55 int main(){ 56 scanf("%d%d",&n,&m); 57 memset(head,-1,sizeof(head)); 58 for(int i=1;i<=n;i++) 59 for(int j=1;j<=m;j++){ 60 scanf("%d",&k); 61 add(0,id,k); 62 ans+=k; 63 } 64 for(int i=1;i<=n;i++) 65 for(int j=1;j<=m;j++){ 66 scanf("%d",&k); 67 add(id,3*n*m+1,k); 68 ans+=k; 69 } 70 for(int i=1;i<=n;i++) 71 for(int j=1;j<=m;j++){ 72 scanf("%d",&k); 73 add(0,n*m+id,k); 74 add(n*m+id,id,inf); 75 if (j>1)add(n*m+id,id-1,inf); 76 if (j<m)add(n*m+id,id+1,inf); 77 if (i>1)add(n*m+id,id-m,inf); 78 if (i<n)add(n*m+id,id+m,inf); 79 ans+=k; 80 } 81 for(int i=1;i<=n;i++) 82 for(int j=1;j<=m;j++){ 83 scanf("%d",&k); 84 add(2*n*m+id,3*n*m+1,k); 85 add(id,2*n*m+id,inf); 86 if (j>1)add(id-1,2*n*m+id,inf); 87 if (j<m)add(id+1,2*n*m+id,inf); 88 if (i>1)add(id-m,2*n*m+id,inf); 89 if (i<n)add(id+m,2*n*m+id,inf); 90 ans+=k; 91 } 92 n=3*n*m+1; 93 printf("%d",ans-dinic()); 94 }