题目描述

有一个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. 阿里云ECS centos7 支持IPv6

    1.编辑 /etc/sysctl.conf 文件,将其中三条禁用IPv6的设置更改为: net.ipv6.conf.all.disable_ipv6 = 0 net.ipv6.conf.default ...

  2. Burpsuite模块—-Intruder模块详解

    一.简介 Burp Intruder是一个强大的工具,用于自动对Web应用程序自定义的攻击,Burp Intruder 是高度可配置的,并被用来在广范围内进行自动化攻击.你可以使用 Burp Intr ...

  3. 微信小程序中在页面中实现下拉刷新显示提醒语后在消失

    最近在做小程序的时候遇见一个问题,就是页面要下拉刷新给客户一个提醒语,查看了小程序的官方文档 这里有个注意点:如果你是一页进行下拉刷新就在那个文件夹的json里面加上"enablePullD ...

  4. c# 类型化变量的var,和javascript一样的使用

    .net framework推出var关键字,注意是关键字,不是什么新类型,只是编译器抛给我们的“语法糖” 1.object是所有类型的父类型,object a=1;和var a=1:的区别在于前一个 ...

  5. 进程间通信___命名管道(FIFO)

    命名管道(FIFO) 基本概念 命名管道和一般的管道基本相同,但也有一些显著的不同: 命名管道是在文件系统中作为一个特殊的设备文件而存在的. 不同祖先的进程之间可以通过管道共享数据. 当共享管道的进程 ...

  6. linux常用命令大全(转)好东西要分享

    1.ls命令 就是list的缩写,通过ls 命令不仅可以查看linux文件夹包含的文件,而且可以查看文件权限(包括目录.文件夹.文件权限)查看目录信息等等 常用参数搭配: ls -a 列出目录所有文 ...

  7. cocos2D-x demo 的源码分析 #define ..##.. 的妙用.

    最近在看cocos2d-x 但不知道如何下手,于是先看一下他编译的完成的testcpp的源码.发现了下面一段程序 typedef CCLayer* (*NEWTESTFUNC)(); #define ...

  8. 银行家算法之JavaScript实现

    上学期有个课程叫做操作系统,期末的时候这课程还有个课程设计,其中有个题目叫做银行家算法. 什么是银行家算法我就不解释了! 看着同学们的设计,大同小异甚至前篇一律. 清一色的控制台程序,清一色的蛋疼输入 ...

  9. jmap, jhat命令

    jmap命令有下面几种常用的用法 jmap [pid] jmap -histo:live [pid] >a.log jmap -dump:live,format=b,file=xxx.xxx [ ...

  10. 594. Longest Harmonious Subsequence强制差距为1的最长连续

    [抄题]: We define a harmonious array is an array where the difference between its maximum value and it ...