题目描述

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

输入输出格式

输入格式:

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

输出格式:

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

输入输出样例

输入样例#1: 复制

3 3
110
000
001
000
110
100
222
222
222
输出样例#1: 复制

4

题解

  费用流好题(说的清楚一点就是我根本不会做……)

  %%%大佬->这里

  首先考虑,我们可以把交换操作,看作是黑色的点在移动

  一个点往下移动的话,当前点和下方的点的交换次数都加一

  然后一条移动的路径,两端的点移动次数加一,中间的点移动次数加二

  如果把这个过程看做网络流的话,就会有一个问题。因为每一个点开始和结束的颜色可能不同,那么流入和流出也不同

  如果只有一个点,就没办法考虑交换次数的限制

  而且如果只拆成两个点的话,就没办法考虑路径两端的情况了

  那么我们把每一个点拆成三个点$left,now,right$,分别表示只有流入,有流入和流出,只有流出

  所以连边$left->now->right$

  然后相互能到达的点之间连边,容$inf$费$0$

  然后考虑如何解决流入流出不平衡

  如果开始为白,之后黑,那么流出必定比流入多一,开始黑,之后白,流入必定比流出多一,颜色一样,那么流入流出一样

  然后交换次数最少,在相邻的格子的边上加上费用

  若该点在初始图中是黑的、最终图中是白的,那么连边$(left,now,1,\frac{limit}{2}),(now,right,1,\frac{limit+1}{2})$

  若该点在初始图中是白的、最终图中是黑的,那么连边$(left,now,1,\frac{limit+1}{2}),(now,right,1,\frac{limit}{2})$

  若该点在初始图和最终图中颜色相同,那么连边$(left,now,1,\frac{limit}{2}),(now,right,1,\frac{limit}{2})$

  这样就可以保证流量限制了

  然后加源,往起始的所有黑点连边,加汇,让最终所有黑点往它连边

  然后在能互相到达的点之间连边

 //minamoto
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define inf 0x3f3f3f3f
#define l(i,j) ((i-1)*m+j)
#define now(i,j) (((i-1)*m+j)+n*m)
#define r(i,j) (((i-1)*m+j)+(n*m<<1))
using namespace std;
const int N=,M=;
int dx[]={,,,,-,-,-,},dy[]={,,-,-,-,,,};
int ver[M],Next[M],head[N],flow[M],edge[M],tot=;
int dis[N],disf[N],Pre[N],last[N],vis[N];
int n,m,ans=,S,T;
queue<int> q;
inline void add(int u,int v,int f,int e){
ver[++tot]=v,Next[tot]=head[u],head[u]=tot,flow[tot]=f,edge[tot]=e;
ver[++tot]=u,Next[tot]=head[v],head[v]=tot,flow[tot]=,edge[tot]=-e;
}
bool spfa(){
memset(dis,0x3f,sizeof(dis));
q.push(S),dis[S]=,disf[S]=inf,Pre[T]=-;
while(!q.empty()){
int u=q.front();q.pop(),vis[u]=;
for(int i=head[u];i;i=Next[i]){
int v=ver[i];
if(flow[i]&&dis[v]>dis[u]+edge[i]){
dis[v]=dis[u]+edge[i],Pre[v]=u,last[v]=i;
disf[v]=min(disf[u],flow[i]);
if(!vis[v]) vis[v]=,q.push(v);
}
}
}
return ~Pre[T];
}
int dinic(){
int maxflow=;
while(spfa()){
int u=T;maxflow+=disf[T],ans+=disf[T]*dis[T];
while(u!=S){
flow[last[u]]-=disf[T];
flow[last[u]^]+=disf[T];
u=Pre[u];
}
}
return maxflow;
}
int x1[][],x2[][],t1,t2;
char s[];
int main(){
scanf("%d%d",&n,&m);
S=,T=n*m*+;
for(int i=;i<=n;++i){
scanf("%s",s+);
for(int j=;j<=m;++j)
if(s[j]==''){
++t1,add(S,now(i,j),,);
x1[i][j]=;
}
}
for(int i=;i<=n;++i){
scanf("%s",s+);
for(int j=;j<=m;++j)
if(s[j]==''){
++t2,add(now(i,j),T,,);
x2[i][j]=;
}
}
if(t1!=t2) return puts("-1"),;
for(int i=;i<=n;++i){
scanf("%s",s+);
for(int j=;j<=m;++j){
t2=s[j]-'';
if(x1[i][j]==x2[i][j])
add(l(i,j),now(i,j),t2/,),add(now(i,j),r(i,j),t2/,);
else if(x1[i][j]&&!x2[i][j])
add(l(i,j),now(i,j),t2/,),add(now(i,j),r(i,j),(t2+)/,);
else
add(l(i,j),now(i,j),(t2+)/,),add(now(i,j),r(i,j),t2/,);
}
}
for(int i=;i<=n;++i)
for(int j=;j<=m;++j)
for(int k=;k<;++k){
int ti=i+dx[k],tj=j+dy[k];
if(ti<||ti>n||tj<||tj>m) continue;
add(r(i,j),l(ti,tj),inf,);
}
if(dinic()!=t1) return puts("-1"),;
printf("%d\n",ans);
return ;
}

BZOJ2668:[CQOI2012]交换棋子(费用流)的更多相关文章

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

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

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

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

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

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

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

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

  5. BZOJ2668: [cqoi2012]交换棋子

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

  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. C++虚函数与纯虚函数用法与区别(转载)

    1. 虚函数和纯虚函数可以定义在同一个类(class)中,含有纯虚函数的类被称为抽象类(abstract class),而只含有虚函数的类(class)不能被称为抽象类(abstract class) ...

  2. Unable to find required classes (javax.activation.DataHandler and javax.mail.internet.MimeMultipart)

    在接触WebService时值得收藏的一篇文章: 在调试Axis1.4访问WebService服务时,出现以下错误: Unable to find required classes (javax.ac ...

  3. docker 制作本地镜像

    docker commit 55ddf8d62688 py_wb # 容器ID, 容器名称tag py_wb IP地址:5000/my-web:20180511 # 远程registory地址 我的镜 ...

  4. 23-从零玩转JavaWeb-单例设计模式

    一.什么是设计模式 二.什么是单例设计模式 三.单例设计模式特点 四.单例设计模式优点 五.单例设计模式实现步骤   六.什么是工具类  

  5. ParksLink修改密码

    设置环境变量: ?set classpath=D:\ptc\PartsLink\srclib\jmxcore\WtLogR.jar;D:\ptc\PartsLink\srclib\log4j.jar; ...

  6. 分布式全文检索系统SolrCloud简介

    前言 本文简单描述SolrCloud的特性,基本结构和入门,基于Solr4.5版本. Lucene是一个Java语言编写的利用倒排原理实现的文本检索类库.Solr是以Lucene为基础实现的文本检索应 ...

  7. 07-Location之正则匹配

    大网站专门有自己的图片服务器,起码也得单独放一个目录里面. 淘宝网有些图片开启了防盗链(即使是小图片,也不让你下载,真小气).163新闻可以下载. 用正则匹配uri中的image,就是说你的uri中到 ...

  8. linux下方便的录屏命令

    linux下方便的录屏命令   ffmpeg -f x11grab -s 1024*768 -r 20 -i :0.0 -sameq ~/recode.mpg -r后是刷新屏率,   推出直接Ctrl ...

  9. jQuery--左侧菜单收缩隐藏

    实现步骤: 步骤一. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 ...

  10. rest-framework-----视图

    一:基本视图 写一个出版社的增删改查的resful接口 路由: url(r'^publish/$', views.PublishView.as_view()), url(r'^publish/(?P& ...