【BZOJ】【2668】【CQOI2012】交换棋子

网络流/费用流


  跪跪跪,居然还可以这样建图……

  题解:http://www.cnblogs.com/zig-zag/archive/2013/04/21/3033485.html

考虑每个点的交换限制的约束,一看就知道是点容量,但是这里不是一分为二,而是一分为三。

首先我们把问题化简,变成对于原图上所有黑点,找到一个新图中的黑点,进行多次交换后到达。我们看到多次交换实际上是走了一条路径(这里不是最短 路)。对于这条路径的起点和终点,仅进行了1次交换,而路径上的其他点都交换了2次。所以我们需要构造一种图来把这个交换次数的差异体现出来,于是:

对于每个点一分为三,分为p0,p1,p2,对于每个点,如果它是原图中得黑点,连 边<p1,p0,c/2,0>,<p0,p2,(c+1)/2>,<st,p0,1,0>;如果它是新图中得黑点, 连边<p1,p0,(c+1)/2>,<p0,p2,c/2,0>,<p0,ed,1,0>;如果它在两个图中都是 白点,那么连边<p1,p0,c/2,0>,<p0,p2,c/2,0>。这样就可以体现出点容量的差异了。

然后对于原图中可以交换的两个点(i,j)连接<pi2,pj1,inf,1>,那么这种边每流过1的流量就意味着(i,j)交换了一次,那么费用就是最终的答案了。

  1 /**************************************************************
  2     Problem: 2668
  3     User: Tunix
  4     Language: C++
  5     Result: Accepted
  6     Time:24 ms
  7     Memory:48464 kb
  8 ****************************************************************/
  9  
 10 //BZOJ 2668
 11 #include<cmath>
 12 #include<vector>
 13 #include<cstdio>
 14 #include<cstring>
 15 #include<cstdlib>
 16 #include<iostream>
 17 #include<algorithm>
 18 #define rep(i,n) for(int i=0;i<n;++i)
 19 #define F(i,j,n) for(int i=j;i<=n;++i)
 20 #define D(i,j,n) for(int i=j;i>=n;--i)
 21 #define pb push_back
 22 using namespace std;
 23 inline int getint(){
 24     int v=0,sign=1; char ch=getchar();
 25     while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();}
 26     while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();}
 27     return v*sign;
 28 }
 29 const int N=20010,M=2000000,INF=~0u>>2;
 30 typedef long long LL;
 31 /******************tamplate*********************/
 32 char s1[50][50],s2[50][50],s3[50][50];
 33 int n,m,a[50][50],b[50][50],c[50][50],num[50][50],b1,b2,ans,flow,tot;
 34 inline int gcd(int a,int b){return b ? gcd(b,a%b) : a;}
 35 bool judge(int x,int y){
 36     int q=x*x-y*y,s=sqrt(q);
 37     if (s*s==q && gcd(y,s)==1) return 1;
 38     return 0;
 39 }
 40 struct edge{int from,to,v,c;};
 41 struct Net{
 42     edge E[M];
 43     int head[N],next[M],cnt;
 44     void ins(int x,int y,int z,int c){
 45         E[++cnt]=(edge){x,y,z,c};
 46         next[cnt]=head[x]; head[x]=cnt;
 47     }
 48     void add(int x,int y,int z,int c){
 49         ins(x,y,z,c); ins(y,x,0,-c);
 50     }
 51     int from[N],Q[M],d[N],S,T;
 52     bool inq[N];
 53     bool spfa(){
 54         int l=0,r=-1;
 55         F(i,0,T) d[i]=INF;
 56         d[S]=0; Q[++r]=S; inq[S]=1;
 57         while(l<=r){
 58             int x=Q[l++];
 59             inq[x]=0;
 60             for(int i=head[x];i;i=next[i])
 61                 if(E[i].v>0 && d[x]+E[i].c<d[E[i].to]){
 62                     d[E[i].to]=d[x]+E[i].c;
 63                     from[E[i].to]=i;
 64                     if (!inq[E[i].to]){
 65                         Q[++r]=E[i].to;
 66                         inq[E[i].to]=1;
 67                     }
 68                 }
 69         }
 70         return d[T]!=INF;
 71     }
 72     void mcf(){
 73         int x=INF,y,z;
 74         for(int i=from[T];i;i=from[E[i].from])
 75             x=min(x,E[i].v);
 76         for(int i=from[T];i;i=from[E[i].from]){
 77             E[i].v-=x;
 78             E[i^1].v+=x;
 79         }
 80         flow+=x;
 81         ans+=x*d[T];
 82     }
 83     void init(){
 84         n=getint(); m=getint(); cnt=1;
 85         tot=n*m; S=0; T=tot*3+1;
 86         F(i,1,n) scanf("%s",s1[i]+1);
 87         F(i,1,n) scanf("%s",s2[i]+1);
 88         F(i,1,n) scanf("%s",s3[i]+1);
 89         F(i,1,n) F(j,1,m){
 90             a[i][j]=s1[i][j]-'0'; if(a[i][j]) b1++;
 91             b[i][j]=s2[i][j]-'0'; if(b[i][j]) b2++;
 92             c[i][j]=s3[i][j]-'0';
 93             if (a[i][j]&&b[i][j]) a[i][j]=b[i][j]=0,b1--,b2--;
 94         }
 95         F(i,1,n) F(j,1,m){
 96             int now=(i-1)*m+j;
 97             num[i][j]=now;
 98             if (a[i][j]){
 99                 add(S,now,1,0);
100                 add(tot+now,now,c[i][j]/2,0);
101                 add(now,2*tot+now,(c[i][j]+1)/2,0);
102             }else if(b[i][j]){
103                 add(now,T,1,0);
104                 add(tot+now,now,(c[i][j]+1)/2,0);
105                 add(now,2*tot+now,c[i][j]/2,0);
106             }else{
107                 add(tot+now,now,c[i][j]/2,0);
108                 add(now,2*tot+now,c[i][j]/2,0);
109             }
110         }
111         F(i,1,n) F(j,1,m){
112             if (i>1) add(2*tot+num[i][j],tot+num[i-1][j],INF,1);
113             if (j>1) add(2*tot+num[i][j],tot+num[i][j-1],INF,1);
114             if (i<n) add(2*tot+num[i][j],tot+num[i+1][j],INF,1);
115             if (j<m) add(2*tot+num[i][j],tot+num[i][j+1],INF,1);
116             if (i>1 && j>1) add(2*tot+num[i][j],tot+num[i-1][j-1],INF,1);
117             if (i<n && j<m) add(2*tot+num[i][j],tot+num[i+1][j+1],INF,1);
118             if (i>1 && j<m) add(2*tot+num[i][j],tot+num[i-1][j+1],INF,1);
119             if (i<n && j>1) add(2*tot+num[i][j],tot+num[i+1][j-1],INF,1);
120         }
121         if (b1==b2){
122             while(spfa()) mcf();
123             if (flow!=b1) ans=-1;
124         }else ans=-1;
125         printf("%d\n",ans);
126     }
127 }G1;
128  
129 int main(){
130 #ifndef ONLINE_JUDGE
131     freopen("input.txt","r",stdin);
132 //  freopen("2668.out","w",stdout);
133 #endif
134     G1.init();
135     return 0;
136 }
View Code

 

posted @ 2015-03-20 18:00  Tunix  阅读(457)  评论(0编辑  收藏  举报