巧妙的拆点方式,首先把1看成黑点,0看成空的,几次交换就可以看成一条路径
1)从容量上看,这条路径为1-2-2-2-2-2-……-2-1
2)从费用上看,这条路径每条边费用都是1
于是用一种巧妙的拆点方式,把一个点拆成三个,连两条边,成为一条链,
然后如果是黑点的话就由s向中间那个点连边,如果是路过的话就由一条链的尾部向另一条链的首部连边
这样就满足了上面的条件1)2)
容量的话如果是黑点出来就是(c+1)/2,进来是c/2,其他的以此类推
1 #include<cstdio> 2 #include<cstdlib> 3 #include<algorithm> 4 #include<cstring> 5 #include<vector> 6 #include<queue> 7 #define rint register int 8 #define ll long long 9 #define MAXN 2000+10 10 #define pb push_back 11 #define INF 0x7f7f7f7f 12 #define oo 0x7f7f7f7f7f7f7f7f 13 #define pil pair<int,ll> 14 #define mp make_pair 15 using namespace std; 16 int read(){ 17 int x=0,f=1;char ch=getchar(); 18 while(ch<‘0‘||ch>‘9‘){if(‘-‘==ch)f=-1;ch=getchar();} 19 while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} 20 return x*f; 21 } 22 struct E{ 23 int from,to,cap,flow; 24 ll cost; 25 E(int x=0,int y=0,int c=0,int f=0,ll w=0LL){ 26 from=x,to=y,cap=c,flow=f,cost=w; 27 } 28 }; 29 struct Dinic{ 30 int n,m,s,t; 31 vector<E> es; 32 vector<int> G[MAXN]; 33 void init(int n,int s,int t){ 34 this->n=n; 35 this->s=s,this->t=t; 36 es.clear(); 37 for(int i=0;i<=n;i++)G[i].clear(); 38 } 39 void add(int x,int y,int cap,ll cost){ 40 es.pb(E(x,y,cap,0,cost)); 41 es.pb(E(y,x,0,0,-cost)); 42 m=es.size(); 43 G[x].pb(m-2),G[y].pb(m-1); 44 } 45 int p[MAXN],a[MAXN]; 46 ll d[MAXN]; 47 int b[MAXN]; 48 bool SPFA(int &flow,ll &cost){ 49 p[s]=0,a[s]=INF; 50 memset(d,0x7f,sizeof(d)); 51 d[s]=0; 52 memset(b,0,sizeof(b)); 53 b[s]=1; 54 queue<int> q; 55 q.push(s); 56 while(!q.empty()){ 57 int x=q.front();q.pop();b[x]=0; 58 for(rint i=0;i<G[x].size();i++){ 59 E &e=es[G[x][i]]; 60 if(e.cap>e.flow&&d[e.to]>d[x]+e.cost){ 61 p[e.to]=G[x][i]; 62 a[e.to]=min(a[x],e.cap-e.flow); 63 d[e.to]=d[x]+e.cost; 64 if(!b[e.to]){ 65 b[e.to]=1; 66 q.push(e.to); 67 } 68 } 69 } 70 } 71 if(oo==d[t]){ 72 return 0; 73 } 74 flow+=a[t]; 75 cost+=a[t]*d[t]; 76 for(rint i=t;i!=s;i=es[p[i]].from){ 77 es[p[i]].flow+=a[t]; 78 es[p[i]^1].flow-=a[t]; 79 } 80 return 1; 81 } 82 pil MaxfMinc(){ 83 int flow=0; 84 ll cost=0LL; 85 while(SPFA(flow,cost)); 86 return mp(flow,cost); 87 } 88 }D; 89 int n,m,s=0,t=MAXN-1; 90 int id[3][25][25]; 91 int a[25][25],b[25][25],p[25][25]; 92 int cnt1=0,cnt2=0; 93 void init(){ 94 n=read();m=read(); 95 D.init(t,s,t); 96 char c[25]; 97 for(rint i=1;i<=n;i++){ 98 for(rint j=1;j<=m;j++){ 99 id[0][i][j]=(i-1)*m+j; 100 } 101 } 102 for(rint k=1;k<=2;k++){ 103 for(rint i=1;i<=n;i++){ 104 for(rint j=1;j<=m;j++){ 105 id[k][i][j]=id[k-1][i][j]+n*m; 106 } 107 } 108 } 109 for(rint i=1;i<=n;i++){ 110 scanf("%s",c+1); 111 for(rint j=1;j<=m;j++){ 112 a[i][j]=c[j]-‘0‘; 113 } 114 } 115 for(rint i=1;i<=n;i++){ 116 scanf("%s",c+1); 117 for(rint j=1;j<=m;j++){ 118 b[i][j]=c[j]-‘0‘; 119 } 120 } 121 for(rint i=1;i<=n;i++){ 122 for(rint j=1;j<=m;j++){ 123 if(a[i][j]&&b[i][j]){ 124 a[i][j]=b[i][j]=0; 125 } 126 else if(a[i][j]){ 127 cnt1++; 128 } 129 else if(b[i][j]){ 130 cnt2++; 131 } 132 } 133 } 134 for(rint i=1;i<=n;i++){ 135 scanf("%s",c+1); 136 for(rint j=1;j<=m;j++){ 137 p[i][j]=c[j]-‘0‘; 138 } 139 } 140 } 141 void add(int x,int y,int c1,int c2){ 142 D.add(id[0][x][y],id[1][x][y],c1,0); 143 D.add(id[1][x][y],id[2][x][y],c2,0); 144 } 145 void solve(){ 146 int dx[8]={0,0,-1,1,-1,-1,1,1}; 147 int dy[8]={1,-1,0,0,-1,1,-1,1}; 148 for(rint i=1;i<=n;i++){ 149 for(rint j=1;j<=m;j++){ 150 if(a[i][j]){ 151 add(i,j,p[i][j]>>1,(p[i][j]+1)>>1); 152 D.add(s,id[1][i][j],1,0); 153 } 154 else if(b[i][j]){ 155 add(i,j,(p[i][j]+1)>>1,p[i][j]>>1); 156 D.add(id[1][i][j],t,1,0); 157 } 158 else{ 159 add(i,j,(p[i][j]+1)>>1,p[i][j]>>1); 160 } 161 for(rint k=0;k<8;k++){ 162 int x=i+dx[k],y=j+dy[k]; 163 if(1<=x&&x<=n&&1<=y&&y<=m){ 164 D.add(id[2][i][j],id[0][x][y],INF,1); 165 } 166 } 167 } 168 } 169 pil ans=D.MaxfMinc(); 170 if(ans.first!=cnt1||cnt1!=cnt2){ 171 printf("-1\n"); 172 } 173 else{ 174 printf("%d\n",ans.second); 175 } 176 } 177 int main() 178 { 179 init(); 180 solve(); 181 return 0; 182 }