标签:min src signed 建模 cstring open case mem ios
题意: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
标签:min src signed 建模 cstring open case mem ios
原文地址:https://www.cnblogs.com/myx12345/p/10035520.html