BZOJ2668: [cqoi2012]交换棋子(费用流)
作者:互联网
Description
有一个n行m列的黑白棋盘,你每次可以交换两个相邻格子(相邻是指有公共边或公共顶点)中的棋子,最终达到目标状态。要求第i行第j列的格子只能参与mi,j次交换。Input
第一行包含两个整数n,m(1<=n, m<=20)。以下n行为初始状态,每行为一个包含m个字符的01串,其中0表示黑色棋子,1表示白色棋子。以下n行为目标状态,格式同初始状态。以下n行每行为一个包含m个0~9数字的字符串,表示每个格子参与交换的次数上限。Output
输出仅一行,为最小交换总次数。如果无解,输出-1。Sample Input
3 3110
000
001
000
110
100
222
222
222
Sample Output
4解题思路:
这道题可以发现费用流肯定是可以解决的。 问题是怎么建图。 易知每步交换一定是一黑一白。 所以就可以考虑每个点前后的变化来得到白变黑次数的上限。 这个只与前后黑白状态有关。 若状态相同,则白变黑次数=黑变白次数。 不同则讨论即可。 一定是一个比另外一个大一。 这样就可以确定流入和流出上限。 现在考虑流量守恒,发现白黑相同时无流量变化,黑白不同时边权也守恒。 发现这样只需要新建两个新节点来达到建图的目的。 代码:1 #include<queue> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 typedef long long lnt; 6 const int oo=0x3f3f3f3f; 7 const int di[8]={0,0,-1,1,1,1,-1,-1}; 8 const int dj[8]={-1,1,0,0,-1,1,1,-1}; 9 struct pnt{ 10 int hd; 11 int dis; 12 int val; 13 int pre; 14 int lst; 15 bool vis; 16 }p[100000]; 17 struct ent{ 18 int twd; 19 int lst; 20 int vls; 21 int dis; 22 }e[1000000]; 23 int cnt; 24 int n,m; 25 int s,t; 26 int maxflow; 27 int no[101][101]; 28 int st[101][101]; 29 int ed[101][101]; 30 int vl[101][101]; 31 std::queue<int>Q; 32 void ade_(int f,int t,int v,int d) 33 { 34 cnt++; 35 e[cnt].twd=t; 36 e[cnt].vls=v; 37 e[cnt].dis=d; 38 e[cnt].lst=p[f].hd; 39 p[f].hd=cnt; 40 return ; 41 } 42 void adde(int f,int t,int v,int d) 43 { 44 ade_(f,t,v,d); 45 ade_(t,f,0,-d); 46 return ; 47 } 48 bool Spfa(void) 49 { 50 while(!Q.empty())Q.pop(); 51 for(int i=1;i<=t;i++) 52 { 53 p[i].dis=p[i].val=oo; 54 p[i].pre=-1; 55 p[i].vis=false; 56 } 57 Q.push(s); 58 p[s].vis=true; 59 p[s].dis=0; 60 while(!Q.empty()) 61 { 62 int x=Q.front(); 63 Q.pop(); 64 p[x].vis=false; 65 for(int i=p[x].hd;i;i=e[i].lst) 66 { 67 int to=e[i].twd; 68 if(p[to].dis>p[x].dis+e[i].dis&&e[i].vls) 69 { 70 p[to].dis=p[x].dis+e[i].dis; 71 p[to].pre=x; 72 p[to].lst=i; 73 p[to].val=std::min(p[x].val,e[i].vls); 74 if(p[to].vis)continue; 75 p[to].vis=true; 76 Q.push(to); 77 } 78 } 79 } 80 return p[t].pre!=-1; 81 } 82 int Ek(void) 83 { 84 int ans=0; 85 while(Spfa()) 86 { 87 maxflow+=p[t].val; 88 ans+=p[t].dis*p[t].val; 89 for(int i=t;i!=s;i=p[i].pre) 90 { 91 e[p[i].lst].vls-=p[t].val; 92 e[((p[i].lst-1)^1)+1].vls+=p[t].val; 93 } 94 } 95 return ans; 96 } 97 int main() 98 { 99 int a1(0),a2(0); 100 scanf("%d%d",&n,&m); 101 for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)no[i][j]=++cnt; 102 s=cnt*3+1,t=s+1; 103 cnt=0; 104 for(int i=1;i<=n;i++) 105 for(int j=1;j<=m;j++) 106 scanf("%1d",&st[i][j]),a1+=st[i][j]; 107 for(int i=1;i<=n;i++) 108 for(int j=1;j<=m;j++) 109 scanf("%1d",&ed[i][j]),a2+=ed[i][j]; 110 for(int i=1;i<=n;i++) 111 for(int j=1;j<=m;j++) 112 scanf("%1d",&vl[i][j]); 113 for(int i=1;i<=n;i++) 114 { 115 for(int j=1;j<=m;j++) 116 { 117 if(!st[i][j])adde(s,no[i][j],1,0); 118 if(!ed[i][j])adde(no[i][j],t,1,0); 119 int frm,twd; 120 if(st[i][j]==ed[i][j])frm=twd=vl[i][j]/2; 121 if(st[i][j]>ed[i][j])frm=(vl[i][j]+1)/2,twd=vl[i][j]/2; 122 if(st[i][j]<ed[i][j])twd=(vl[i][j]+1)/2,frm=vl[i][j]/2; 123 adde(no[i][j]+n*m,no[i][j],frm,0); 124 adde(no[i][j],no[i][j]+2*n*m,twd,0); 125 for(int d=0;d<8;d++) 126 { 127 int ii=di[d]+i; 128 int jj=dj[d]+j; 129 if(!no[ii][jj])continue; 130 adde(no[i][j]+2*n*m,no[ii][jj]+m*n,oo,1); 131 132 } 133 } 134 } 135 int ans=Ek(); 136 if(m*n-maxflow!=a1||a1!=a2)ans=-1; 137 printf("%d\n",ans); 138 return 0; 139 }
标签:cnt,val,int,cqoi2012,BZOJ2668,lst,棋子,101,dis 来源: https://www.cnblogs.com/blog-Dr-J/p/10440725.html