1. 程式人生 > >【HDOJ5520】Number Link(費用流)

【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\n",v,ans); 160 else printf("Case #%d: -1\n",v); 161 } 162 return 0; 163 } 164