bzoj2668 [cqoi2012]交换棋子
2013-04-21 09:49
218 查看
费用流题,构图非常巧妙。
考虑每个点的交换限制的约束,一看就知道是点容量,但是这里不是一分为二,而是一分为三。
首先我们把问题化简,变成对于原图上所有黑点,找到一个新图中的黑点,进行多次交换后到达。我们看到多次交换实际上是走了一条路径(这里不是最短路)。对于这条路径的起点和终点,仅进行了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)交换了一次,那么费用就是最终的答案了。
chess
考虑每个点的交换限制的约束,一看就知道是点容量,但是这里不是一分为二,而是一分为三。
首先我们把问题化简,变成对于原图上所有黑点,找到一个新图中的黑点,进行多次交换后到达。我们看到多次交换实际上是走了一条路径(这里不是最短路)。对于这条路径的起点和终点,仅进行了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)交换了一次,那么费用就是最终的答案了。
chess
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #define maxn 2000 #define maxm 50000 #define inf 2147483647 using namespace std; struct et { int s,t,val,cost,next; }e[maxm]; char s1[100][100],s2[100][100],s3[100][100]; int a[100][100],b[100][100],c[100][100],num[100][100]; int fir[maxn],q[maxm],d[maxn],pre[maxn]; bool inque[maxn]; int n,m,st,ed,tot,ans,b1,b2,fare; bool find() { for (int i=st;i<=ed;i++) d[i]=inf; int head=0,tail=1; q[1]=st; d[st]=0; inque[st]=1; while (head<tail) { int now=q[++head]; for (int j=fir[now];j;j=e[j].next) { int k=e[j].t; if (e[j].val&&d[k]>d[now]+e[j].cost) { pre[k]=j; d[k]=d[now]+e[j].cost; if (!inque[k]) q[++tail]=k,inque[k]=1; } } inque[now]=0; } return d[ed]<inf; } void fare_flow() { for (int i=1;i<=b1;i++) { find(); int tmp=inf; for (int j=pre[ed];j;j=pre[e[j].s]) tmp=min(tmp,e[j].val); fare+=tmp*d[ed]; ans+=tmp; for (int j=pre[ed];j;j=pre[e[j].s]) e[j].val-=tmp,e[j^1].val+=tmp; } } void add(int x,int y,int z,int w) { e[++tot].s=x; e[tot].t=y; e[tot].val=z; e[tot].cost=w; e[tot].next=fir[x]; fir[x]=tot; e[++tot].s=y; e[tot].t=x; e[tot].val=0; e[tot].cost=-w; e[tot].next=fir[y]; fir[y]=tot; } int main() { //freopen("chess1.in","r",stdin); scanf("%d%d",&n,&m); st=0; ed=n*m*3+1; tot=1; for (int i=1;i<=n;i++) scanf("%s",s1[i]+1); for (int i=1;i<=n;i++) scanf("%s",s2[i]+1); for (int i=1;i<=n;i++) scanf("%s",s3[i]+1); for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) { 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--; } for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) { int now=(i-1)*m+j; num[i][j]=now; if (a[i][j]) { add(st,now,1,0); add(n*m+now,now,c[i][j]/2,0); add(now,2*n*m+now,(c[i][j]+1)/2,0); } else if (b[i][j]) { add(now,ed,1,0); add(n*m+now,now,(c[i][j]+1)/2,0); add(now,2*n*m+now,c[i][j]/2,0); } else { add(n*m+now,now,c[i][j]/2,0); add(now,2*n*m+now,c[i][j]/2,0); } } for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) { if (i>1) add(2*n*m+num[i][j],n*m+num[i-1][j],inf,1); if (j>1) add(2*n*m+num[i][j],n*m+num[i][j-1],inf,1); if (i<n) add(2*n*m+num[i][j],n*m+num[i+1][j],inf,1); if (j<m) add(2*n*m+num[i][j],n*m+num[i][j+1],inf,1); if (i>1&&j>1) add(2*n*m+num[i][j],n*m+num[i-1][j-1],inf,1); if (i<n&&j<m) add(2*n*m+num[i][j],n*m+num[i+1][j+1],inf,1); if (i>1&&j<m) add(2*n*m+num[i][j],n*m+num[i-1][j+1],inf,1); if (i<n&&j>1) add(2*n*m+num[i][j],n*m+num[i+1][j-1],inf,1); } //for (int i=2;i<=tot;i++) cout<<e[i].s<<' '<<e[i].t<<' '<<e[i].val<<' '<<e[i].cost<<endl; fare=0; if (b1==b2){ fare_flow(); if (ans!=b1) fare=-1; } else fare=-1; printf("%d\n",fare); return 0; }
相关文章推荐
- BZOJ2668:[CQOI2012]交换棋子(费用流)
- BZOJ2668:[CQOI2012]交换棋子——题解
- BZOJ2668: [cqoi2012]交换棋子 费用流
- bzoj2668 [cqoi2012]交换棋子
- 【bzoj2668】【cqoi2012】【交换棋子】【费用流】
- BZOJ 2668 CQOI 2012 交换棋子 费用流
- [BZOJ2668][CQOI2012]交换棋子(费用流)
- BZOJ2668 [cqoi2012]交换棋子 【费用流】
- 【BZOJ2668】[cqoi2012]交换棋子 费用流
- CQOI2012 交换棋子
- 洛谷P3159 [CQOI2012]交换棋子
- 【BZOJ】【2668】【CQOI2012】交换棋子
- [bzoj2668] [cqoi2012]交换棋子
- 【BZOJ2668】【cqoi2012】交换棋子 费用流
- bzoj2668 [cqoi2012]交换棋子
- [BZOJ2668][CQOI2012]交换棋子
- BZOJ 2668: [cqoi2012]交换棋子
- 【bzoj 2668】: [cqoi2012]交换棋子
- [CQOI2012][bzoj2668] 交换棋子 [费用流]
- BZOJ 2668: [cqoi2012]交换棋子(费用流)