您的位置:首页 > 其它

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

2015-03-20 18:00 190 查看

网络流/费用流

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

  题解:/article/6145383.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)交换了一次,那么费用就是最终的答案了。



/**************************************************************
Problem: 2668
User: Tunix
Language: C++
Result: Accepted
Time:24 ms
Memory:48464 kb
****************************************************************/

//BZOJ 2668
#include<cmath>
#include<vector>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define rep(i,n) for(int i=0;i<n;++i)
#define F(i,j,n) for(int i=j;i<=n;++i)
#define D(i,j,n) for(int i=j;i>=n;--i)
#define pb push_back
using namespace std;
inline int getint(){
int v=0,sign=1; char ch=getchar();
while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();}
while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();}
return v*sign;
}
const int N=20010,M=2000000,INF=~0u>>2;
typedef long long LL;
/******************tamplate*********************/
char s1[50][50],s2[50][50],s3[50][50];
int n,m,a[50][50],b[50][50],c[50][50],num[50][50],b1,b2,ans,flow,tot;
inline int gcd(int a,int b){return b ? gcd(b,a%b) : a;}
bool judge(int x,int y){
int q=x*x-y*y,s=sqrt(q);
if (s*s==q && gcd(y,s)==1) return 1;
return 0;
}
struct edge{int from,to,v,c;};
struct Net{
edge E[M];
int head
,next[M],cnt;
void ins(int x,int y,int z,int c){
E[++cnt]=(edge){x,y,z,c};
next[cnt]=head[x]; head[x]=cnt;
}
void add(int x,int y,int z,int c){
ins(x,y,z,c); ins(y,x,0,-c);
}
int from
,Q[M],d
,S,T;
bool inq
;
bool spfa(){
int l=0,r=-1;
F(i,0,T) d[i]=INF;
d[S]=0; Q[++r]=S; inq[S]=1;
while(l<=r){
int x=Q[l++];
inq[x]=0;
for(int i=head[x];i;i=next[i])
if(E[i].v>0 && d[x]+E[i].c<d[E[i].to]){
d[E[i].to]=d[x]+E[i].c;
from[E[i].to]=i;
if (!inq[E[i].to]){
Q[++r]=E[i].to;
inq[E[i].to]=1;
}
}
}
return d[T]!=INF;
}
void mcf(){
int x=INF,y,z;
for(int i=from[T];i;i=from[E[i].from])
x=min(x,E[i].v);
for(int i=from[T];i;i=from[E[i].from]){
E[i].v-=x;
E[i^1].v+=x;
}
flow+=x;
ans+=x*d[T];
}
void init(){
n=getint(); m=getint(); cnt=1;
tot=n*m; S=0; T=tot*3+1;
F(i,1,n) scanf("%s",s1[i]+1);
F(i,1,n) scanf("%s",s2[i]+1);
F(i,1,n) scanf("%s",s3[i]+1);
F(i,1,n) F(j,1,m){
a[i][j]=s1[i][j]-'0'; if(a[i][j]) b1++;
b[i][j]=s2[i][j]-'0'; if(b[i][j]) b2++;
c[i][j]=s3[i][j]-'0';
if (a[i][j]&&b[i][j]) a[i][j]=b[i][j]=0,b1--,b2--;
}
F(i,1,n) F(j,1,m){
int now=(i-1)*m+j;
num[i][j]=now;
if (a[i][j]){
add(S,now,1,0);
add(tot+now,now,c[i][j]/2,0);
add(now,2*tot+now,(c[i][j]+1)/2,0);
}else if(b[i][j]){
add(now,T,1,0);
add(tot+now,now,(c[i][j]+1)/2,0);
add(now,2*tot+now,c[i][j]/2,0);
}else{
add(tot+now,now,c[i][j]/2,0);
add(now,2*tot+now,c[i][j]/2,0);
}
}
F(i,1,n) F(j,1,m){
if (i>1) add(2*tot+num[i][j],tot+num[i-1][j],INF,1);
if (j>1) add(2*tot+num[i][j],tot+num[i][j-1],INF,1);
if (i<n) add(2*tot+num[i][j],tot+num[i+1][j],INF,1);
if (j<m) add(2*tot+num[i][j],tot+num[i][j+1],INF,1);
if (i>1 && j>1) add(2*tot+num[i][j],tot+num[i-1][j-1],INF,1);
if (i<n && j<m) add(2*tot+num[i][j],tot+num[i+1][j+1],INF,1);
if (i>1 && j<m) add(2*tot+num[i][j],tot+num[i-1][j+1],INF,1);
if (i<n && j>1) add(2*tot+num[i][j],tot+num[i+1][j-1],INF,1);
}
if (b1==b2){
while(spfa()) mcf();
if (flow!=b1) ans=-1;
}else ans=-1;
printf("%d\n",ans);
}
}G1;

int main(){
#ifndef ONLINE_JUDGE
freopen("input.txt","r",stdin);
//  freopen("2668.out","w",stdout);
#endif
G1.init();
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: