题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2668
题意:有一个n行m列的黑白棋盘,你每次可以交换两个相邻格子中的棋子,最终达到目标状态。要求第i行第j列的格子只能参与m[i,j]次交换。
思路: 我们将1看做要移动的数字,将0看做空白。那么若1在始末状态个数不同则无解;如某个格子始末状态均有1则这个格子的1对结果无影响,可以将其都置为0。将每个格子拆为为个点p0,p1,p2:
(1)若格子初始为1,则连边:<s,p0,1,0>,<p1,p0,m[i][j]/2,0)>,<p0,p2,(m[i][j]+1)/2,0>;
(2)若格子末状态为0,则连边:<p0,t,1,0>,<p1,p0,(m[i][j]+1)/2,0>,<p0,p2,m[i][j]/2,0>;
(3)始末都是空白,则连边:<p1,p0,m[i][j]/2,0>,<p0,p2,m[i][j]/2,0>;
(4)相邻格子x和y连边<px2,py1,INF,0>。
struct node { int u,v,next,cost,cap; }; node edges[N]; int head[N],e; void add(int u,int v,int cap,int cost) { edges[e].u=u; edges[e].v=v; edges[e].cap=cap; edges[e].cost=cost; edges[e].next=head[u]; head[u]=e++; } void Add(int u,int v,int cap,int cost) { add(u,v,cap,cost); add(v,u,0,-cost); } int pre[N],F[N],C[N],visit[N]; int SPFA(int s,int t,int n) { int i; for(i=0;i<=n;i++) F[i]=0,C[i]=INF,visit[i]=0; queue<int> Q; Q.push(s); F[s]=INF; C[s]=0; int u,v,cost,cap; while(!Q.empty()) { u=Q.front(); Q.pop(); visit[u]=0; for(i=head[u];i!=-1;i=edges[i].next) { if(edges[i].cap>0) { v=edges[i].v; cost=edges[i].cost; cap=edges[i].cap; if(C[v]>C[u]+cost) { C[v]=C[u]+cost; F[v]=min(F[u],cap); pre[v]=i; if(!visit[v]) visit[v]=1,Q.push(v); } } } } return F[t]; } char a[25][25],b[25][25],c[25][25]; int d[25][25][3]; int dx[]={-1,-1,-1,0,1,1,1,0}; int dy[]={-1,0,1,1,1,0,-1,-1}; int n,m,s,t,cnt; int ans; int MCMF(int s,int t,int n) { int i,x,temp,M=0; while(temp=SPFA(s,t,n)) { M+=temp; for(i=t;i!=s;i=edges[pre[i]].u) { x=pre[i]; ans+=edges[x].cost*temp; edges[x].cap-=temp; edges[x^1].cap+=temp; } } return M==cnt; } int main() { RD(n,m); int i,j; FOR1(i,n) RD(a[i]+1); FOR1(i,n) RD(b[i]+1); FOR1(i,n) RD(c[i]+1); int k=0; FOR1(i,n) FOR1(j,m) { a[i][j]-='0'; b[i][j]-='0'; c[i][j]-='0'; d[i][j][0]=++k; d[i][j][1]=++k; d[i][j][2]=++k; if(a[i][j]&&b[i][j]) a[i][j]=0,b[i][j]=0; } s=0; t=++k; clr(head,-1); cnt=0; int x,y,p=0; FOR1(i,n) FOR1(j,m) { if(a[i][j]) { cnt++; Add(s,d[i][j][0],1,0); Add(d[i][j][1],d[i][j][0],c[i][j]/2,0); Add(d[i][j][0],d[i][j][2],(c[i][j]+1)/2,0); } else if(b[i][j]) { p++; Add(d[i][j][0],t,1,0); Add(d[i][j][1],d[i][j][0],(c[i][j]+1)/2,0); Add(d[i][j][0],d[i][j][2],c[i][j]/2,0); } else { Add(d[i][j][1],d[i][j][0],c[i][j]/2,0); Add(d[i][j][0],d[i][j][2],c[i][j]/2,0); } FOR0(k,8) { x=i+dx[k]; y=j+dy[k]; if(x>=1&&x<=n&&y>=1&&y<=m) { Add(d[i][j][2],d[x][y][1],INF,1); } } } if(cnt!=p||!MCMF(s,t,t+1)) puts("-1"); else PR(ans); }