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

时间:2023-02-13 17:18:04

2668: [cqoi2012]交换棋子

Time Limit: 3 Sec  Memory Limit: 128 MB
Submit: 1055  Solved: 388
[Submit][Status][Discuss]

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

HINT

Source

Solution

这是一道建图比较有趣的费用流.

想到用费用流比较容易,很显然,连法必然是S连向原图中的黑点,新图中的黑点连向T,问题在于中间的连边,如何利用容量限制两个点。

自己一开始立马想到拆点,但是是很naive的一拆二,限制容量,但这样并不可以。

实际上这个题需要一个点拆成3个点,我们把点$x$拆成$x_{1},x_{2},x_{3}$,并连出$x_{1}-->x_{2}-->x_{3}$

其中$x_{1}-->x_{2}$表示$x$这个点最多流入的流量,$x_{2}-->x_{3}$表示$x$这个点最多流出的流量。

对于一个点$x$,如果只是原图的黑点,那么限制$<x_{1},x_{2}>:cap=\frac{use[x]}{2};cost=0 ; <x_{2},x_{3}>:cap=\frac{use[x]+1}{2};cost=0$

并且连$S-->x_{2} : cap=1;cost=0$

对于一个点$x$,如果只是新图的黑点,那么限制$<x_{1},x_{2}>:cap=\frac{use[x]+1}{2};cost=0 ; <x_{2},x_{3}>:cap=\frac{use[x]}{2};cost=0$

并且连$x_{2}-->T : cap=1;cost=0$

如果一个点$x$,如果在原图和新图中都是白点或者都是黑点,那么我们限制$<x_{1},x_{2}>:cap=\frac{use[x]}{2};cost=0 ; <x_{2},x_{3}>:cap=\frac{use[x]}{2};cost=0$

对于图中的八连通格两两$x ; y$,连边$x_{3}-->y_{1} :cap=INF ; cost=1$流经此边,表示交换一次。

上述的限制方法,实际上是对网格的每个位置的流量变化进行讨论得到的,因为是一个最值情况,所以很多流入流出限制都无法完全流满。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
#define MAXM 100010
#define MAXN 2000
int N,M,used[][];
char st[][],ed[][],us[][];
struct EdgeNode{int next,to,cap,cost;}edge[MAXM];
int cnt=,head[MAXN];
inline void AddEdge(int u,int v,int w,int c) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v; edge[cnt].cap=w; edge[cnt].cost=c;}
inline void InsertEdge(int u,int v,int w,int c) {AddEdge(u,v,w,c); AddEdge(v,u,,-c);}
int dis[MAXN],S,T,Cost,Flow;
bool mark[MAXN];
#define INF 0x7fffffff
inline bool SPFA()
{
memset(mark,,sizeof(mark));
for (int i=S; i<=T; i++) dis[i]=INF;
queue<int>q;
q.push(S); dis[S]=; mark[S]=;
while (!q.empty())
{
int now=q.front(); q.pop(); mark[now]=;
for (int i=head[now]; i; i=edge[i].next)
if (edge[i].cap && dis[edge[i].to]>dis[now]+edge[i].cost)
{
dis[edge[i].to]=dis[now]+edge[i].cost;
if (!mark[edge[i].to]) q.push(edge[i].to),mark[edge[i].to]=;
}
}
return dis[T]!=INF;
}
inline int DFS(int loc,int low)
{
mark[loc]=;
if (loc==T) return low;
int used=,w;
for (int i=head[loc]; i; i=edge[i].next)
if (edge[i].cap && !mark[edge[i].to] && dis[edge[i].to]==dis[loc]+edge[i].cost)
{
w=DFS(edge[i].to,min(edge[i].cap,low-used));
edge[i].cap-=w; edge[i^].cap+=w; used+=w; Cost+=w*edge[i].cost;
if (low==used) return used;
}
return used;
}
inline int zkw()
{
int re=;
while (SPFA())
{
mark[T]=;
while (mark[T]) memset(mark,,sizeof(mark)),re+=DFS(S,INF);
}
return re;
}
int id[][][],ID,black,white;
int dx[]={-,-,-,,,,,},dy[]={-,,,-,,-,,};
inline bool check(int x,int y) {return x>= && x<=N && y>= && y<=M;}
void BuildGraph()
{
for (int i=; i<=N; i++)
for (int j=; j<=M; j++)
for (int k=; k<=; k++)
id[i][j][k]=++ID;
S=,T=ID+;
for (int i=; i<=N; i++)
for (int j=; j<=M; j++)
{
if (st[i][j]=='' && ed[i][j]=='')
black++,
InsertEdge(S,id[i][j][],,),
InsertEdge(id[i][j][],id[i][j][],used[i][j]/,),
InsertEdge(id[i][j][],id[i][j][],(used[i][j]+)/,);
if (st[i][j]=='' && ed[i][j]=='')
white++,
InsertEdge(id[i][j][],T,,),
InsertEdge(id[i][j][],id[i][j][],(used[i][j]+)/,),
InsertEdge(id[i][j][],id[i][j][],used[i][j]/,);
if (st[i][j]==ed[i][j])
InsertEdge(id[i][j][],id[i][j][],used[i][j]/,),
InsertEdge(id[i][j][],id[i][j][],used[i][j]/,);
}
for (int i=; i<=N; i++)
for (int j=; j<=M; j++)
for (int x,y,k=; k<; k++)
{
x=i+dx[k],y=j+dy[k];
if (check(x,y)) InsertEdge(id[i][j][],id[x][y][],INF,);
}
}
int main()
{
scanf("%d%d",&N,&M);
for (int i=; i<=N; i++) scanf("%s",st[i]+);
for (int i=; i<=N; i++) scanf("%s",ed[i]+);
for (int i=; i<=N; i++) scanf("%s",us[i]+);
for (int i=; i<=N; i++)
for (int j=; j<=M; j++) used[i][j]=us[i][j]-'';
BuildGraph();
Flow=zkw();
printf("%d\n",black==white? (Flow==black? Cost : -) : -);
return ;
}

脑残RE了好几次...

【BZOJ-2668】交换棋子 最小费用最大流的更多相关文章

  1. BZOJ 2668 &lbrack;cqoi2012&rsqb;交换棋子 &vert; 最小费用最大流

    传送门 BZOJ 2668 题解 同时分别限制流入和流出次数,所以把一个点拆成三个:入点in(x).中间点mi(x).出点ou(x). 如果一个格子x在初始状态是黑点,则连(S, mi(x), 1, ...

  2. BZOJ 2668 交换棋子(费用流)

    题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2668 题意:有一个n行m列的黑白棋盘,你每次可以交换两个相邻格子中的棋子,最终达到目标状 ...

  3. BZOJ 1927 星际竞速&lpar;最小费用最大流&rpar;

    题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1927 题意:一个图,n个点.对于给出的每条边 u,v,w,表示u和v中编号小的那个到编号 ...

  4. BZOJ 2424&colon; &lbrack;HAOI2010&rsqb;订货&lpar;最小费用最大流&rpar;

    最小费用最大流..乱搞即可 ------------------------------------------------------------------------------ #includ ...

  5. &lbrack;BZOJ 2668&rsqb; 交换棋子

    Link: BZOJ 2668 传送门 Solution: 重点在于对于每条转移路径:首尾算一次,中间节点算两次 可以一点拆三点,将原流量拆成入流量和出流量 但其实也可以就拆两点,分前后是否是一首尾点 ...

  6. BZOJ 1070&colon; &lbrack;SCOI2007&rsqb;修车 &lbrack;最小费用最大流&rsqb;

    1070: [SCOI2007]修车 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 4936  Solved: 2032[Submit][Status] ...

  7. bzoj 1061 志愿者招募&lpar;最小费用最大流&rpar;

    [Noi2008]志愿者招募 Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 3792  Solved: 2314[Submit][Status][Di ...

  8. BZOJ 3550 Vacation(最小费用最大流)

    题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3550 题意:给出3×n个数字,从中选出一些数字,要求每连续的n个数字中选出的数字个 ...

  9. BZOJ 2597 剪刀石头布(最小费用最大流)(WC2007)

    Description 在一些一对一游戏的比赛(如下棋.乒乓球和羽毛球的单打)中,我们经常会遇到A胜过B,B胜过C而C又胜过A的有趣情况,不妨形象的称之为剪刀石头布情况.有的时候,无聊的人们会津津乐道 ...

随机推荐

  1. &lbrack;转载&rsqb; 对象存储&lpar;2&rpar;:OpenStack Swift——概念、架构与规模部署

    原文: http://www.testlab.com.cn/Index/article/id/1085.html#rd?sukey=fc78a68049a14bb228cb2742bdec2b9498 ...

  2. 画表格防OFFICE的功能

    http://files.cnblogs.com/xe2011/officetable.rar 画表格防OFFICE的功能

  3. 大牛博客!Spark &sol; Hadoop &sol; Kafka &sol; HBase &sol; Storm

    在这里,非常感谢下面的著名大牛们,一路的帮助和学习,给予了我很大的动力! 有了Hadoop,再次有了Spark,一次又一次,一晚又一晚的努力相伴! HBase简介(很好的梳理资料) 1. 博客主页:h ...

  4. inputtype

    <EditText android:layout_width="fill_parent" android:layout_height="wrap_content&q ...

  5. Spring &plus; Mybatis&&num;160&semi;集成原理分析

    由于我之前是写在wizNote上的,迁移过来比较浪费时间,所以,这里我直接贴个图片,PDF文件我上传到百度云盘了,需要的可直接下载. 地址:https://pan.baidu.com/s/12ZJmw ...

  6. NIagara Workbench &lpar; 温度控制&rpar;

    1.在原来BoilerControl的基础上建立一个 2.检查通过标签构造的报告的时候,在键盘上按下Control键并一直保持的同时按下L键 将会弹窗一个ORD窗口代表定义的参数.同时按下Contro ...

  7. 延迟提交form

    提交按钮延迟提交form表单 function a(){document.getElementById('form1').submit();}setTimeout(a,5000);

  8. c&num; 执行javascript 脚本

    /// <summary> /// 执行JS /// this.ExecuteScript("get('{0}')".FormatWith(token0), File. ...

  9. 第四周读书笔记——读《我是一只IT小小鸟》有感

             读<我是一只IT小小鸟>有感 这是邓老师倾力推荐的一本书.这本书的标题化用了我们耳熟能详的歌词,算是较有新意吧.更重点在于,这本书的作者不是哪一位大牛,而是一群刚刚走出校 ...

  10. Java ThreadLocal的使用

    Java中的ThreadLocal类允许我们创建只能被同一个线程读写的变量.因此,如果一段代码含有一个ThreadLocal变量的引用,即使两个线程同时执行这段代码,它们也无法访问到对方的Thread ...