【BZOJ2668】[cqoi2012]交换棋子

Description

有一个nm列的黑白棋盘,你每次可以交换两个相邻格子(相邻是指有公共边或公共顶点)中的棋子,最终达到目标状态。要求第i行第j列的格子只能参与mi,j次交换。

Input

第一行包含两个整数nm(1<=nm<=20)。以下n行为初始状态,每行为一个包含m个字符的01串,其中0表示黑色棋子,1表示白色棋子。以下n行为目标状态,格式同初始状态。以下n行每行为一个包含m个0~9数字的字符串,表示每个格子参与交换的次数上限。

Output

输出仅一行,为最小交换总次数。如果无解,输出-1。

Sample Input

3 3
110
000
001
000
110
100
222
222
222

Sample Output

4

题解:容易想到费用流,从S向原图中所有1连边,新图中所有1向T连边,中间边的费用是1。但是中间的边我们既要限制入度又要限制出度,该怎么连呢?

我们仔细观察发现,如果相邻的两个都是1或都是0肯定不会交换,也就是说我们每次交换都会导致当前点的颜色改变。即如果当前点原图是0新图是0或原图是1新图是1,则该点的入度=出度;如果原图是1新图是0,则入度+1=出度;原图是0新图是1,则入度=出度+1。这样的话解个方程就知道具体的入度和出度限制了,所以我们只需要限制一下入度即可。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
queue<int> q;
int n,m,ta,tb,S,T,cnt,ans;
char s1[30][30],s2[30][30],s3[30][30];
inline int _(int a,int b) {return (a-1)*m+b;}
inline int __(int a,int b) {return (a-1)*m+b+n*m;}
int to[400010],next[400010],head[1010],cost[400010],flow[400010],dis[1010],pe[1010],pv[1010],inq[1010];
inline void add(int a,int b,int c,int d)
{
to[cnt]=b,cost[cnt]=c,flow[cnt]=d,next[cnt]=head[a],head[a]=cnt++;
to[cnt]=a,cost[cnt]=-c,flow[cnt]=0,next[cnt]=head[b],head[b]=cnt++;
}
inline int bfs()
{
memset(dis,0x3f,sizeof(dis));
dis[S]=0,q.push(S);
int i,u;
while(!q.empty())
{
u=q.front(),q.pop(),inq[u]=0;
for(i=head[u];i!=-1;i=next[i]) if(flow[i]&&dis[to[i]]>dis[u]+cost[i])
{
dis[to[i]]=dis[u]+cost[i],pe[to[i]]=i,pv[to[i]]=u;
if(!inq[to[i]]) inq[to[i]]=1,q.push(to[i]);
}
}
return dis[T]<0x3f3f3f3f;
}
int main()
{
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&m),S=0,T=2*n*m+1;
int i,j,a,b;
for(i=1;i<=n;i++)
{
scanf("%s",s1[i]+1);
for(j=1;j<=m;j++) if(s1[i][j]=='1') ta++,add(S,_(i,j),0,1);
}
for(i=1;i<=n;i++)
{
scanf("%s",s2[i]+1);
for(j=1;j<=m;j++) if(s2[i][j]=='1') tb++,add(_(i,j),T,0,1);
}
if(ta!=tb)
{
puts("-1");
return 0;
}
for(i=1;i<=n;i++)
{
scanf("%s",s3[i]+1);
for(j=1;j<=m;j++)
{
if(s3[i][j]-'0'-s1[i][j]+s2[i][j]<0)
{
puts("-1");
return 0;
}
add(__(i,j),_(i,j),1,(s3[i][j]-'0'-s1[i][j]+s2[i][j])>>1);
for(a=i-1;a<=i+1;a++) for(b=j-1;b<=j+1;b++) if((a!=i||b!=j)&&a&&b&&a<=n&&b<=m)
add(_(i,j),__(a,b),0,1<<30);
}
}
while(bfs())
{
ta--,ans+=dis[T];
for(i=T;i!=S;i=pv[i]) flow[pe[i]]--,flow[pe[i]^1]++;
}
printf("%d",ta?-1:ans);
return 0;
}//1 3 100 001 121

【BZOJ2668】[cqoi2012]交换棋子 费用流的更多相关文章

  1. BZOJ2668: [cqoi2012]交换棋子(费用流)

    Description 有一个n行m列的黑白棋盘,你每次可以交换两个相邻格子(相邻是指有公共边或公共顶点)中的棋子,最终达到目标状态.要求第i行第j列的格子只能参与mi,j次交换. Input 第一行 ...

  2. [CQOI2012] 交换棋子 - 费用流

    有一个n行m列的黑白棋盘,你每次可以交换两个相邻格子(相邻是指有公共边或公共顶点)中的棋子,最终达到目标状态.要求第i行第j列的格子只能参与mi,j次交换. Solution 一个点拆三份,入点,主点 ...

  3. BZOJ.2668.[CQOI2012]交换棋子(费用流zkw)

    题目链接 首先黑白棋子的交换等价于黑棋子在白格子图上移动,都到达指定位置. 在这假设我们知道这题用网络流做. 那么黑棋到指定位置就是一条路径,考虑怎么用流模拟出这条路径. 我们发现除了路径的起点和终点 ...

  4. BZOJ2668: [cqoi2012]交换棋子

    题解: 可以戳这里:http://www.cnblogs.com/zig-zag/archive/2013/04/21/3033485.html 其实自己yy一下就知道这样建图的正确性了. 感觉太神奇 ...

  5. BZOJ2668:[CQOI2012]交换棋子(费用流)

    题目描述 有一个n行m列的黑白棋盘,你每次可以交换两个相邻格子(相邻是指有公共边或公共顶点)中的棋子,最终达到目标状态.要求第i行第j列的格子只能参与mi,j次交换. 输入输出格式 输入格式: 第一行 ...

  6. BZOJ2668 [cqoi2012]交换棋子 【费用流】

    题目链接 BZOJ2668 题解 容易想到由\(S\)向初始的黑点连边,由终态的黑点向\(T\)连边,然后相邻的点间连边 但是这样满足不了交换次数的限制,也无法计算答案 考虑如何满足一个点的交换次数限 ...

  7. [CQOI2012][bzoj2668] 交换棋子 [费用流]

    题面 传送门 思路 抖机灵 一开始看到这题我以为是棋盘模型-_-|| 然而现实是骨感的 后来我尝试使用插头dp来交换,然后又惨死 最后我不得不把目光转向那个总能化腐朽为神奇的算法:网络流 思维 我们要 ...

  8. 【BZOJ-2668】交换棋子 最小费用最大流

    2668: [cqoi2012]交换棋子 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 1055  Solved: 388[Submit][Status ...

  9. [cqoi2012]交换棋子

      2668: [cqoi2012]交换棋子 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 1334  Solved: 518[Submit][Stat ...

随机推荐

  1. HTML(二):表格元素

    表格元素的作用:用来格式化显示数据. 一.表格的基本结构 表格的基本语法:<TABLE border="设置表格边框尺寸大小" width="" cell ...

  2. GDI+(一):GDI+ 绘图基础

    一.GDI+绘图基础 编写图形程序时需要使用GDI(Graphics Device Interface,图形设备接口),从程序设计的角度看,GDI包括两部分:一部分是GDI对象,另一部分是GDI函数. ...

  3. scp基本使用方法

    scp基本使用方法: scp用于在两台电脑之间进行数据的copy,形式如下:  第一种, scp [-r] 文件/文件夹  user@host:dir ,需要输入密码.  第二种, scp [-r] ...

  4. linux下node-webkit安装vlc插件

    一.下载node-webkit 下载linux版本的node-webkit,网址如下:https://github.com/rogerwang/node-webkit.文件解压之后又如下几个文件,其中 ...

  5. Windoows窗口程序六

    #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <stri ...

  6. main函数位置

    c语言中main函数的位置可以任意位置.在执行一个c语言编写的程序时,main函数就相当于是执行程序的入口.只要是没有语法和逻辑上的错误,main函数可以放在任意位置.

  7. Collections 集合工具类

    集合工具类  包括很多静态方法来操作集合list 而Collections则是集合类的一个工具类/帮助类,其中提供了一系列静态方法,用于对集合中元素进行排序.搜索以及线程安全等各种操作. 1) 排序( ...

  8. Batch Normalization原理及其TensorFlow实现——为了减少深度神经网络中的internal covariate shift,论文中提出了Batch Normalization算法,首先是对”每一层“的输入做一个Batch Normalization 变换

    批标准化(Bactch Normalization,BN)是为了克服神经网络加深导致难以训练而诞生的,随着神经网络深度加深,训练起来就会越来越困难,收敛速度回很慢,常常会导致梯度弥散问题(Vanish ...

  9. linux -- Ubuntu Server 安装图形界面

    1.连接网络,你一定要确保网络通畅,如果你和我一样使用Wireless,那先找根网线插上,因为下面的安装都要通过网络下载组件的. 2.进入图形界面的命令是startX,敲击后会有安装xinit的提示. ...

  10. html -- 实体