【HDOJ5520】Number Link(费用流)

题意:NxM的格子有些上面有数字,现在要把奇数跟偶数配对连起来,其他的格子连成一个个回路,

单独的相邻两个格子相连也算是一个回路按两条边算,连线不能相交,

给出相邻两个格子相连的费用,求最小的总费用,无解输出-1

n,m<=50

保证答案在int范围之内

思路:费用流神仙建模

From https://blog.csdn.net/ahi219/article/details/51454133

把每个格子拆成两个点,然后如下连边:

源点向左边的奇数格子和空格子连容量为1,费用为0的边。

右边的偶数格子和空格子向汇点连容量为1,费用为0的边。

左边的格子向右边相邻的格子连容量为1,费用为cost的边。

这样求一遍最小费用最大流即可,如果不是满流,则为无解。

这样建模的原因是把每空格子拆成入点和出点,奇数只有入点,偶数只有出点。

这样保证了每个空格子会有一个入度和一个出度,要么成环,要么参与到奇偶相连中。

奇数只有出度偶数只有出度保证了一定是奇数连向偶数。

这样求一遍费用流最后就是结果,如果不是满流说明有的点没连上所以无解。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<string>
  4 #include<cmath>
  5 #include<iostream>
  6 #include<algorithm>
  7 #include<map>
  8 #include<set>
  9 #include<queue>
 10 #include<vector>
 11 using namespace std;
 12 typedef long long ll;
 13 typedef unsigned int uint;
 14 typedef unsigned long long ull;
 15 typedef pair<int,int> PII;
 16 typedef vector<int> VI;
 17 #define fi first
 18 #define se second 
 19 #define MP make_pair
 20 #define N      31000
 21 #define M      51
 22 #define MOD 1000000007
 23 #define eps 1e-8 
 24 #define pi     acos(-1)
 25 #define oo     1010000000
 26 
 27 bool inq[N];
 28 int num[M][M][2],a[M][M],
 29     q[N],dis[N],head[N],vet[N],nxt[N],len1[N],len2[N],fan[N],pre[N][2],
 30     n,source,src,tot,s,ans,flow;
 31     
 32 void add(int a,int b,int c,int d)
 33 {
 34     nxt[++tot]=head[a];
 35     vet[tot]=b;
 36     len1[tot]=c;
 37     len2[tot]=d;
 38     head[a]=tot;
 39     
 40     nxt[++tot]=head[b];
 41     vet[tot]=a;
 42     len1[tot]=0;
 43     len2[tot]=-d;
 44     head[b]=tot;
 45 }
 46 
 47 bool spfa()
 48 {
 49     for(int i=1;i<=s;i++)
 50     {
 51         dis[i]=oo;
 52         inq[i]=false;
 53     }
 54     int t=0; int w=1;
 55     q[1]=source; dis[source]=0; inq[source]=true;
 56     while(t<w)
 57     {
 58         t++; int u=q[t%(s+5)]; inq[u]=false;
 59         int e=head[u];
 60         while(e)
 61         {
 62             int v=vet[e];
 63             if(len1[e]&&dis[u]+len2[e]<dis[v])
 64             {
 65                 dis[v]=dis[u]+len2[e];
 66                 pre[v][1]=u;
 67                 pre[v][2]=e;
 68                 if(!inq[v])
 69                 {
 70                     w++; q[w%(s+5)]=v; inq[v]=true;
 71                 }
 72             }
 73             e=nxt[e];
 74         }
 75     }
 76     return (dis[src]!=oo);
 77 }
 78 
 79 void mcf()
 80 {
 81     int k=src;
 82     int t=oo;
 83     while(k!=source)
 84     {
 85         int e=pre[k][2];
 86         t=min(t,len1[e]);
 87         k=pre[k][1];    
 88     }
 89     k=src;
 90     while(k!=source)
 91     {
 92         int e=pre[k][2];
 93         len1[e]-=t;
 94         len1[fan[e]]+=t;
 95         ans+=t*len2[e];
 96         k=pre[k][1];
 97     }
 98     flow+=t;
 99 }
100 
101 void init()
102 {
103     memset(head,0,sizeof(head));
104     memset(pre,0,sizeof(pre));
105     tot=0;
106 }
107 
108 int main()
109 { 
110     freopen("hdoj5520.in","r",stdin);
111     //freopen("hdoj5520.out","w",stdout);
112     for(int i=1;i<N;i++)
113      if(i&1) fan[i]=i+1;
114       else fan[i]=i-1; 
115      int cas;
116      scanf("%d",&cas);
117      for(int v=1;v<=cas;v++) 
118      {
119          int n,m;
120          scanf("%d%d",&n,&m);
121          int F=0;
122          for(int i=1;i<=n;i++)
123           for(int j=1;j<=m;j++) 
124           {
125               scanf("%d",&a[i][j]);
126               if(a[i][j]==0) F++;
127               if(a[i][j]&&a[i][j]%2==1) F++;
128           }    
129          s=0;
130          for(int i=1;i<=n;i++)
131           for(int j=1;j<=m;j++)
132            for(int k=0;k<=1;k++) num[i][j][k]=++s;
133          init();
134          source=s+1; src=s+2; s+=2;
135          for(int i=1;i<=n;i++)
136           for(int j=1;j<=m;j++)
137           {
138               if(a[i][j]==0||a[i][j]%2==1) add(source,num[i][j][0],1,0);
139               if(a[i][j]==0||a[i][j]%2==0) add(num[i][j][1],src,1,0);
140           }
141          for(int i=1;i<=n-1;i++)
142           for(int j=1;j<=m;j++)
143           {
144               int x;
145               scanf("%d",&x);
146              add(num[i][j][0],num[i+1][j][1],1,x);
147              add(num[i+1][j][0],num[i][j][1],1,x);
148           }
149          for(int i=1;i<=n;i++)
150           for(int j=1;j<=m-1;j++)
151           {
152               int x;
153               scanf("%d",&x);
154               add(num[i][j][0],num[i][j+1][1],1,x);
155             add(num[i][j+1][0],num[i][j][1],1,x);
156          }
157         ans=0; flow=0;
158         while(spfa()) mcf();
159         if(flow==F) printf("Case #%d: %d
",v,ans);
160          else printf("Case #%d: -1
",v);
161     }
162     return 0;
163 }
164     
原文地址:https://www.cnblogs.com/myx12345/p/10035520.html