题目描述

有一个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. Redhat 无线(Wifi)上网命令行配置

    小结两种命令行模式下配置无线wife的方法,实践测试通过(Red Hat Enterprise Linux release 6.0 Beta(Santiago)) 一.使用wpa_supplicant ...

  2. 转gif图

    用QQ影音截取影片 + Ulead GIF Animator510编辑.

  3. leetcode452

    public class Solution { public int FindMinArrowShots(int[,] points) { // multidimensional array cann ...

  4. mysql 存储过程变量的定义

    Mysql变量: 1.DECLARE variable_name datatype(size) DEFAULT default_value; 此处声明的相当于一个局部变量 ,在end 之后便失效. 声 ...

  5. vue 构建前端项目并关联github

    这几天尝试用node开发一个网站,后端的接口已经初步开发完成,现在开始构建前端的项目,记录下过程,在学习下吧. 用vue-cli 构建项目,myproject.(构架过程略过) 每次在本地构建项目后和 ...

  6. C++深度解析教程学习笔记(6)对象的构造和销毁

    1. 对象的初始化 (1)从程序设计的角度看,对象只是变量,因此: ①在栈上创建对象时,成员变量初始化为随机值 ②在堆上创建对象时,成员变量初始化为随机值 ③在静态存储区创建对象时,成员变量初始化为 ...

  7. HTML_基础篇

    一.HTML的概述 什么是HTML? html:Hyper Test Markup Language 超文本标记语言(它不是编程语言!) 超文本:功能比普通的文本更加强大. 标记语言:使用一组标签对内 ...

  8. Java多线程-线程的同步(同步代码块)

    对于同步,除了同步方法外,还可以使用同步代码块,有时候同步代码块会带来比同步方法更好的效果. 追其同步的根本的目的,是控制竞争资源的正确的访问,因此只要在访问竞争资源的时候保证同一时刻只能一个线程访问 ...

  9. 如何判定Unity已破解成功

    [如何判定Unity已破解成功] 点击菜单“Unity”->"About Unity...".在弹出的关于Unity的信息的对话框中,如果是已破解版本,在右下角会显示序列号.

  10. IP定位,天气接口

    首先获取IP ////获得本地真实IP function get_onlineip() { $ip_json = @file_get_contents("http://ip.taobao.c ...