[国家集训队2011]happiness(最小割)

Link   (https://www.luogu.org/problemnew/solution/P1646)

网络流中最大流与最小割的建图方式完全不同,比如本题中就要将选文理两科分连向S和T,最小割会将方阵中的点分别连向两点,即分成两类。再把联携收益S->tp->(i,j),(i,j+1)这样子,这样的话如果两格点在同一集合中,就会得到联携收益。(注意网络流不要写丑...)

  1 #include <queue>
  2 #include <cstdio>
  3 #include <cstdlib>
  4 #include <cstring>
  5 #include <algorithm>
  6 using namespace std;
  7 int n,m,S,T,SUM=0; const int N=110,INF=0x3f3f3f3f;
  8 int val;
  9 // int v0[N][N],v1[N][N];
 10 // int e01[N][N],e02[N][N],e11[N][N],e12[N][N];
 11 
 12 //-----Qxx----->
 13 const int MAXN=N*N*6,MAXM=MAXN*12;
 14 int head[MAXN],Next[MAXM],ver[MAXM],tot=1; int edge[MAXM];
 15 void link(int u,int v,int w){
 16       ver[++tot]=v,Next[tot]=head[u],head[u]=tot; edge[tot]=w;
 17       ver[++tot]=u,Next[tot]=head[v],head[v]=tot; edge[tot]=0;
 18 }
 19 
 20 int p[N][N],cnt=0; //point's rank int the tot graph
 21 void build()
 22 {
 23       scanf("%d %d",&n,&m); S=++cnt; T=++cnt;
 24       for(int i=1;i<=n;i++){
 25             for(int j=1;j<=m;j++){
 26                   scanf("%d",&val); SUM+=val;
 27                   p[i][j]=++cnt; link(S,p[i][j],val);
 28             }
 29       }
 30       for(int i=1;i<=n;i++){
 31             for(int j=1;j<=m;j++){
 32                   scanf("%d",&val); SUM+=val;
 33                   link(p[i][j],T,val);
 34             }
 35       }
 36 
 37       for(int i=1;i<n;i++){
 38             for(int j=1;j<=m;j++){
 39                   scanf("%d",&val); SUM+=val;
 40                   int tp=++cnt; link(S,tp,val); link(tp,p[i][j],INF); link(tp,p[i+1][j],INF);
 41             }
 42       }
 43       for(int i=1;i<n;i++){
 44             for(int j=1;j<=m;j++){
 45                   scanf("%d",&val); SUM+=val;
 46                   int tp=++cnt; link(tp,T,val); link(p[i][j],tp,INF); link(p[i+1][j],tp,INF);
 47             }
 48       }
 49 
 50       for(int i=1;i<=n;i++){
 51             for(int j=1;j<m;j++){
 52                   scanf("%d",&val); SUM+=val;
 53                   int tp=++cnt; link(S,tp,val); link(tp,p[i][j],INF); link(tp,p[i][j+1],INF);
 54             }
 55       }
 56       for(int i=1;i<=n;i++){
 57             for(int j=1;j<m;j++){
 58                   scanf("%d",&val); SUM+=val;
 59                   int tp=++cnt; link(tp,T,val); link(p[i][j],tp,INF); link(p[i][j+1],tp,INF);
 60             }
 61       }
 62 }
 63 
 64 //-----Dinic----->
 65 int d[MAXN];
 66 queue <int> Q;
 67 bool bfs()
 68 {
 69       while(!Q.empty()) Q.pop();
 70       memset(d,0,sizeof(d));
 71       Q.push(S); d[S]=1;
 72       while(!Q.empty())
 73       {
 74             int x=Q.front(); Q.pop();
 75             for(int i=head[x];i;i=Next[i]){
 76                   int v=ver[i];
 77                   if(!d[v]&&edge[i]>0){
 78                         d[v]=d[x]+1;
 79                         if(v==T) return true ;
 80                         Q.push(v);
 81                   }
 82             }
 83       }
 84       return false ;
 85 }
 86 
 87 int cur[MAXN];
 88 int dfs(int x,int Flow)
 89 {
 90       if(x==T) return Flow;
 91       int tmp=Flow;
 92       for(int &i=cur[x];i&&tmp>0;i=Next[i]){
 93             int v=ver[i];
 94             if(d[v]==d[x]+1&&edge[i]>0){
 95                   int k=dfs(v,min(edge[i],tmp));
 96                   if(k==0){ d[v]=0; continue ; }
 97                   tmp-=k; edge[i]-=k,edge[i^1]+=k;
 98             }
 99       }
100       return Flow-tmp;
101 }
102 
103 void work()
104 {
105       int minicut=0;
106       while(bfs()){
107           for(int i=1;i<=cnt;i++) cur[i]=head[i];
108             minicut+=dfs(S,INF);
109         }
110       printf("%d\n",SUM-minicut);
111 }
112 
113 
114 int main()
115 {
116       build();
117       work();
118       return 0;
119 }

 

posted @ 2019-05-10 19:46  Shdityr  阅读(128)  评论(0编辑  收藏  举报