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

解题思路:

这道题可以发现费用流肯定是可以解决的。
问题是怎么建图。
易知每步交换一定是一黑一白。
所以就可以考虑每个点前后的变化来得到白变黑次数的上限。
这个只与前后黑白状态有关。
若状态相同,则白变黑次数=黑变白次数。
不同则讨论即可。
一定是一个比另外一个大一。
这样就可以确定流入和流出上限。
现在考虑流量守恒,发现白黑相同时无流量变化,黑白不同时边权也守恒。
发现这样只需要新建两个新节点来达到建图的目的。
代码:
 #include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
typedef long long lnt;
const int oo=0x3f3f3f3f;
const int di[]={,,-,,,,-,-};
const int dj[]={-,,,,-,,,-};
struct pnt{
int hd;
int dis;
int val;
int pre;
int lst;
bool vis;
}p[];
struct ent{
int twd;
int lst;
int vls;
int dis;
}e[];
int cnt;
int n,m;
int s,t;
int maxflow;
int no[][];
int st[][];
int ed[][];
int vl[][];
std::queue<int>Q;
void ade_(int f,int t,int v,int d)
{
cnt++;
e[cnt].twd=t;
e[cnt].vls=v;
e[cnt].dis=d;
e[cnt].lst=p[f].hd;
p[f].hd=cnt;
return ;
}
void adde(int f,int t,int v,int d)
{
ade_(f,t,v,d);
ade_(t,f,,-d);
return ;
}
bool Spfa(void)
{
while(!Q.empty())Q.pop();
for(int i=;i<=t;i++)
{
p[i].dis=p[i].val=oo;
p[i].pre=-;
p[i].vis=false;
}
Q.push(s);
p[s].vis=true;
p[s].dis=;
while(!Q.empty())
{
int x=Q.front();
Q.pop();
p[x].vis=false;
for(int i=p[x].hd;i;i=e[i].lst)
{
int to=e[i].twd;
if(p[to].dis>p[x].dis+e[i].dis&&e[i].vls)
{
p[to].dis=p[x].dis+e[i].dis;
p[to].pre=x;
p[to].lst=i;
p[to].val=std::min(p[x].val,e[i].vls);
if(p[to].vis)continue;
p[to].vis=true;
Q.push(to);
}
}
}
return p[t].pre!=-;
}
int Ek(void)
{
int ans=;
while(Spfa())
{
maxflow+=p[t].val;
ans+=p[t].dis*p[t].val;
for(int i=t;i!=s;i=p[i].pre)
{
e[p[i].lst].vls-=p[t].val;
e[((p[i].lst-)^)+].vls+=p[t].val;
}
}
return ans;
}
int main()
{
int a1(),a2();
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)for(int j=;j<=m;j++)no[i][j]=++cnt;
s=cnt*+,t=s+;
cnt=;
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
scanf("%1d",&st[i][j]),a1+=st[i][j];
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
scanf("%1d",&ed[i][j]),a2+=ed[i][j];
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
scanf("%1d",&vl[i][j]);
for(int i=;i<=n;i++)
{
for(int j=;j<=m;j++)
{
if(!st[i][j])adde(s,no[i][j],,);
if(!ed[i][j])adde(no[i][j],t,,);
int frm,twd;
if(st[i][j]==ed[i][j])frm=twd=vl[i][j]/;
if(st[i][j]>ed[i][j])frm=(vl[i][j]+)/,twd=vl[i][j]/;
if(st[i][j]<ed[i][j])twd=(vl[i][j]+)/,frm=vl[i][j]/;
adde(no[i][j]+n*m,no[i][j],frm,);
adde(no[i][j],no[i][j]+*n*m,twd,);
for(int d=;d<;d++)
{
int ii=di[d]+i;
int jj=dj[d]+j;
if(!no[ii][jj])continue;
adde(no[i][j]+*n*m,no[ii][jj]+m*n,oo,); }
}
}
int ans=Ek();
if(m*n-maxflow!=a1||a1!=a2)ans=-;
printf("%d\n",ans);
return ;
}

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

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

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

  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. 移植u-boot-2014.4到S5PV210/TQ210(完整)

    本文很多其它的是教会大家怎样学习 1.1   概述 1.2   u-boot配置过程分析 1.3   u-boot编译过程分析 1.4   SPL 1.5   加入自己的单板 1.6   移植u-bo ...

  2. nodejs微服务健康检查方案

    1. 前言 针对目前云平台方案,因为网络.主机状态等诸多因素,单台主机上的服务出现问题的几率大大增加.这就要求我们能够监控每台主机.每个微服务实例的健康状态.因此对于nodejs相关项目需要做相关的微 ...

  3. 重写MPAndroidChart显示标记

    MPAndroidChart是实现图表功能的优秀控件, 能够完毕大多数绘制需求. 对于改动第三方库而言, 优秀的架构是继承开发, 而不是把源代码拆分出去. MP在显示标记控件(MarkView)时, ...

  4. Scala学习笔记及与Java不同之处总结-从Java开发者角度

    Scala与Java具有很多相似之处,但又有很多不同.这里主要从一个Java开发者的角度,总结在使用Scala的过程中所面临的一些思维转变. 这里仅仅是总结了部分两种语言在开发过程中的不同,以后会陆续 ...

  5. bzoj4873: [Shoi2017]寿司餐厅(最大权闭合子图)

    4873: [Shoi2017]寿司餐厅 大难题啊啊!!! 题目:传送门 题解:一眼题是网络流,但还是不会OTZ,菜啊... %题解... 最大权闭合子图!!! 好的...开始花式建边: 1.对于每个 ...

  6. rsync同步操作命令

    在本地磁盘同步数据 将/home做个备份 # rsync -a --delete /home /backups -a 归档模式,表示以递归方式传输文件, -delete 删除那些接收端还有而发送端已经 ...

  7. 7.stack

    #include <iostream> #include <stack> #include <algorithm> #include <list> #i ...

  8. ListView有Header时的position情况

     问题: headerView 为第0个view,item 的 pos会从1开始. 解决方式: position减去 listView.getHeaderViewsCount().例如我想得到list ...

  9. bzoj 1588 [HNOI2002] 营业额统计 链表和Splay

    来自HNOI 2002营业额的统计一题,这题以前是用链表水过的,最近看见许多splay的题,赶紧张一下知识. 题目大意就是对于一个序列,输出每个元素与它之前元素的差的最小值的和.先说链表的方法吧. 大 ...

  10. Ubuntu下哪个PDF阅读器更好使???

    根据windows系统上的经验,果断选择了foxit reader的linux版本: 从 http://www.foxitsoftware.com/downloads/ 选择 “Desktop Lin ...