BZOJ2668:[CQOI2012]交换棋子(费用流)
题目描述
有一个n行m列的黑白棋盘,你每次可以交换两个相邻格子(相邻是指有公共边或公共顶点)中的棋子,最终达到目标状态。要求第i行第j列的格子只能参与mi,j次交换。
输入输出格式
输入格式:
第一行包含两个整数n,m(1<=n, m<=20)。以下n行为初始状态,每行为一个包含m个字符的01串,其中0表示黑色棋子,1表示白色棋子。以下n行为目标状态,格式同初始状态。以下n行每行为一个包含m个0~9数字的字符串,表示每个格子参与交换的次数上限。
输出格式:
输出仅一行,为最小交换总次数。如果无解,输出-1。
输入输出样例
3 3
110
000
001
000
110
100
222
222
222
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]交换棋子(费用流)的更多相关文章
- BZOJ2668: [cqoi2012]交换棋子(费用流)
Description 有一个n行m列的黑白棋盘,你每次可以交换两个相邻格子(相邻是指有公共边或公共顶点)中的棋子,最终达到目标状态.要求第i行第j列的格子只能参与mi,j次交换. Input 第一行 ...
- 【BZOJ2668】[cqoi2012]交换棋子 费用流
[BZOJ2668][cqoi2012]交换棋子 Description 有一个n行m列的黑白棋盘,你每次可以交换两个相邻格子(相邻是指有公共边或公共顶点)中的棋子,最终达到目标状态.要求第i行第j列 ...
- [CQOI2012] 交换棋子 - 费用流
有一个n行m列的黑白棋盘,你每次可以交换两个相邻格子(相邻是指有公共边或公共顶点)中的棋子,最终达到目标状态.要求第i行第j列的格子只能参与mi,j次交换. Solution 一个点拆三份,入点,主点 ...
- BZOJ.2668.[CQOI2012]交换棋子(费用流zkw)
题目链接 首先黑白棋子的交换等价于黑棋子在白格子图上移动,都到达指定位置. 在这假设我们知道这题用网络流做. 那么黑棋到指定位置就是一条路径,考虑怎么用流模拟出这条路径. 我们发现除了路径的起点和终点 ...
- BZOJ2668: [cqoi2012]交换棋子
题解: 可以戳这里:http://www.cnblogs.com/zig-zag/archive/2013/04/21/3033485.html 其实自己yy一下就知道这样建图的正确性了. 感觉太神奇 ...
- BZOJ2668 [cqoi2012]交换棋子 【费用流】
题目链接 BZOJ2668 题解 容易想到由\(S\)向初始的黑点连边,由终态的黑点向\(T\)连边,然后相邻的点间连边 但是这样满足不了交换次数的限制,也无法计算答案 考虑如何满足一个点的交换次数限 ...
- [CQOI2012][bzoj2668] 交换棋子 [费用流]
题面 传送门 思路 抖机灵 一开始看到这题我以为是棋盘模型-_-|| 然而现实是骨感的 后来我尝试使用插头dp来交换,然后又惨死 最后我不得不把目光转向那个总能化腐朽为神奇的算法:网络流 思维 我们要 ...
- 【BZOJ-2668】交换棋子 最小费用最大流
2668: [cqoi2012]交换棋子 Time Limit: 3 Sec Memory Limit: 128 MBSubmit: 1055 Solved: 388[Submit][Status ...
- [cqoi2012]交换棋子
2668: [cqoi2012]交换棋子 Time Limit: 3 Sec Memory Limit: 128 MBSubmit: 1334 Solved: 518[Submit][Stat ...
随机推荐
- 阿里云ECS centos7 支持IPv6
1.编辑 /etc/sysctl.conf 文件,将其中三条禁用IPv6的设置更改为: net.ipv6.conf.all.disable_ipv6 = 0 net.ipv6.conf.default ...
- Burpsuite模块—-Intruder模块详解
一.简介 Burp Intruder是一个强大的工具,用于自动对Web应用程序自定义的攻击,Burp Intruder 是高度可配置的,并被用来在广范围内进行自动化攻击.你可以使用 Burp Intr ...
- 微信小程序中在页面中实现下拉刷新显示提醒语后在消失
最近在做小程序的时候遇见一个问题,就是页面要下拉刷新给客户一个提醒语,查看了小程序的官方文档 这里有个注意点:如果你是一页进行下拉刷新就在那个文件夹的json里面加上"enablePullD ...
- c# 类型化变量的var,和javascript一样的使用
.net framework推出var关键字,注意是关键字,不是什么新类型,只是编译器抛给我们的“语法糖” 1.object是所有类型的父类型,object a=1;和var a=1:的区别在于前一个 ...
- 进程间通信___命名管道(FIFO)
命名管道(FIFO) 基本概念 命名管道和一般的管道基本相同,但也有一些显著的不同: 命名管道是在文件系统中作为一个特殊的设备文件而存在的. 不同祖先的进程之间可以通过管道共享数据. 当共享管道的进程 ...
- linux常用命令大全(转)好东西要分享
1.ls命令 就是list的缩写,通过ls 命令不仅可以查看linux文件夹包含的文件,而且可以查看文件权限(包括目录.文件夹.文件权限)查看目录信息等等 常用参数搭配: ls -a 列出目录所有文 ...
- cocos2D-x demo 的源码分析 #define ..##.. 的妙用.
最近在看cocos2d-x 但不知道如何下手,于是先看一下他编译的完成的testcpp的源码.发现了下面一段程序 typedef CCLayer* (*NEWTESTFUNC)(); #define ...
- 银行家算法之JavaScript实现
上学期有个课程叫做操作系统,期末的时候这课程还有个课程设计,其中有个题目叫做银行家算法. 什么是银行家算法我就不解释了! 看着同学们的设计,大同小异甚至前篇一律. 清一色的控制台程序,清一色的蛋疼输入 ...
- jmap, jhat命令
jmap命令有下面几种常用的用法 jmap [pid] jmap -histo:live [pid] >a.log jmap -dump:live,format=b,file=xxx.xxx [ ...
- 594. Longest Harmonious Subsequence强制差距为1的最长连续
[抄题]: We define a harmonious array is an array where the difference between its maximum value and it ...