2668: [cqoi2012]交换棋子

Time Limit: 3 Sec  Memory Limit: 128 MB
Submit: 1334  Solved: 518
[Submit][Status][Discuss]

Description

有一个nm列的黑白棋盘,你每次可以交换两个相邻格子(相邻是指有公共边或公共顶点)中的棋子,最终达到目标状态。要求第i行第j列的格子只能参与mi,j次交换。

Input

第一行包含两个整数nm(1<=n, m<=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

 

[Submit][Status][Discuss]

HOME
Back


 

费用流,建图神建图。。。

照例说建图,看上去貌似毫无头绪,然而实际上还是可做的,首先可以看到有一个步数上限,自然就往网络流那边想,然后求最小交换的步数,应该貌似看上去是求一个最小费用,所以费用流。

首先自然是要拆点,比较特殊的是,这个题一个点拆三个点。。。。我们分别叫他们x,y,z,首先先从源点向所有是一的y点连一条容量为1,免费的边,从y点向汇点也这么连。然后对于这两张图,如果第一张图中有棋子,那么就连v[i][j]/2从x到y,(v[i][j]+1)/2从y到z,如果只是第二张图里有,那么就换换加一。最后把所有能互相影响的点从z到x连无限流0费的边,一遍费用流即可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define ll long long
#define inf 500000000
#define re register
#define id ((i-1)*m+j)
using namespace std;
struct po
{
int from,to,dis,nxt,w;
}edge[];
int head[],dep[],n,m,s,t,u,num=-,x,y,l,tot,sum,k,fa[];
int dis[],b[],xb[],flow[];
char map1[][],map2[][],mapn[][],cnt;
int dx[]={,-,-,-,,,,,};
int dy[]={,-,,,,,,-,-};
inline long long read()
{
long long x=,c=;
char ch=' ';
while((ch<''||ch>'')&&ch!='-')ch=getchar();
while(ch=='-')c*=-,ch=getchar();
while(ch>=''&&ch<='')x=x*+ch-'',ch=getchar();
return x*c;
}
inline void add_edge(int from,int to,int w,int dis)
{
edge[++num].nxt=head[from];
edge[num].to=to;
edge[num].w=w;
edge[num].dis=dis;
head[from]=num;
}
inline void add(int from,int to,int w,int dis)
{
add_edge(from,to,w,dis);
add_edge(to,from,,-dis);
}
inline bool spfa()
{
memset(b,,sizeof(b));
for(re int i=;i<=t;i++)
dis[i]=inf;
deque<int> q;
b[t]=;dis[t]=;
q.push_back(t);
while(!q.empty())
{
int u=q.front();
q.pop_front();
b[u]=;
for(re int i=head[u];i!=-;i=edge[i].nxt)
{
int v=edge[i].to;
if(edge[i^].w>&&dis[v]>dis[u]-edge[i].dis)
{
dis[v]=dis[u]-edge[i].dis;
if(!b[v])
{
b[v]=;
if(!q.empty()&&dis[v]>dis[q.front()])
q.push_front(v);
else
q.push_back(v);
}
}
}
}
return dis[s]<inf;
}
inline int dfs(int u,int low)
{
if(u==t)
{
b[t]=;
return low;
}
int diss=;
b[u]=;
for(re int i=head[u];i!=-;i=edge[i].nxt)
{
int v=edge[i].to;
if(!b[v]&&edge[i].w!=&&dis[v]==dis[u]-edge[i].dis)
{
int check=dfs(v,min(low,edge[i].w));
if(check>)
{
tot+=check*edge[i].dis;
low-=check;
diss+=check;
edge[i].w-=check;
edge[i^].w+=check;
if(low==) break;
}
}
}
return diss;
}
inline int max_flow()
{
int ans=;
while(spfa())
{
b[t]=;
while(b[t])
{
memset(b,,sizeof(b));
ans+=dfs(s,inf);
}
}
return ans;
}
int main()
{
memset(head,-,sizeof(head));
n=read();m=read();
s=;t=n*m*+;
int N=n*m;
for(re int i=;i<=n;i++)
for(re int j=;j<=m;j++){
cin>>map1[i][j];
if(map1[i][j]=='') add(s,id+N,,),cnt++;
}
for(re int i=;i<=n;i++)
for(re int j=;j<=m;j++){
cin>>map2[i][j];
if(map2[i][j]=='') add(id+N,t,,);
}
for(re int i=;i<=n;i++)
for(re int j=;j<=m;j++)
cin>>mapn[i][j];
for(re int i=;i<=n;i++)
for(re int j=;j<=m;j++){
if(map1[i][j]==map2[i][j]==''){
add(id,id+N,(mapn[i][j]-'')/,);add(id+N,id+N+N,(mapn[i][j]-'')/,);
}else if(map1[i][j]==''){
add(id,id+N,(mapn[i][j]-'')/,);add(id+N,id+N+N,(mapn[i][j]+-'')/,);
}else if(map2[i][j]==''){
add(id,id+N,(mapn[i][j]+-'')/,);add(id+N,id+N+N,(mapn[i][j]-'')/,);
}else add(id,id+N,(mapn[i][j]-'')/,),add(id+N,id+N+N,(mapn[i][j]-'')/,);
for(re int k=;k<=;k++){
int lx=dx[k]+i; int ly=dy[k]+j;
if(lx>=&&lx<=n&&ly>=&&ly<=m){
add(id+N+N,(lx-)*m+ly,inf,);
}
}
}
sum=max_flow();
if(sum>=cnt) cout<<tot;
else cout<<"-1";
}

[cqoi2012]交换棋子的更多相关文章

  1. BZOJ2668: [cqoi2012]交换棋子

    题解: 可以戳这里:http://www.cnblogs.com/zig-zag/archive/2013/04/21/3033485.html 其实自己yy一下就知道这样建图的正确性了. 感觉太神奇 ...

  2. BZOJ 2668: [cqoi2012]交换棋子

    2668: [cqoi2012]交换棋子 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 1112  Solved: 409[Submit][Status ...

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

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

  4. 洛谷 P3159(BZOJ 2668)[CQOI2012]交换棋子

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

  5. P3159 [CQOI2012]交换棋子

    思路 相当神奇的费用流拆点模型 最开始我想到把交换黑色棋子看成一个流流动的过程,流从一个节点流向另一个节点就是交换两个节点,然后把一个位置拆成两个点限制流量,然后就有了这样的建图方法 S向所有初始是黑 ...

  6. BZOJ.2668.[CQOI2012]交换棋子(费用流zkw)

    题目链接 首先黑白棋子的交换等价于黑棋子在白格子图上移动,都到达指定位置. 在这假设我们知道这题用网络流做. 那么黑棋到指定位置就是一条路径,考虑怎么用流模拟出这条路径. 我们发现除了路径的起点和终点 ...

  7. 2668: [cqoi2012]交换棋子

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

  8. [CQOI2012]交换棋子 网络流

    ---题面--- 题解: 一开始很快想出了一个接近正解的建图方法,但其实是错误的,不过还是骗了70分_(:зゝ∠)_ 首先我们可以观察到棋子有限,但费用多种,其实也就相当于限制了流量,找最小费用 对于 ...

  9. BZOJ2668:[CQOI2012]交换棋子——题解

    http://www.lydsy.com/JudgeOnline/problem.php?id=2668 https://www.luogu.org/problemnew/show/P3159#sub ...

随机推荐

  1. 服务器之ECC报错检查

    需要使用ipmitool工具 [root@Resource ~]# yum install ipmitool 首先查看是否有ecc报错 如下图: [root@Resource ~]# ipmitool ...

  2. SAP系统自带的function module

    SAP有很多系统自带的FM,直接在Pattern中就可以调出.---test 1.     KD_GET_FILENAME_ON_F4 ---------------------用以在windows ...

  3. WINDOWS 7.1 SDK 安装失败

    错误提示: Please refer to Samples\Setup\HTML\ConfigDetails.htm document for further information. 原因:本机上安 ...

  4. 1070 Bash游戏 V4

    1070 Bash游戏 V4 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题 有一堆石子共有N个.A B两个人轮流拿,A先拿.每次拿的数量最少1个,最多不超过对手上 ...

  5. 剖析与优化 Go 的 web 应用

    https://mp.weixin.qq.com/s/HDsbZLOK3h8-XjejvPH2sA https://studygolang.com/articles/12685

  6. text files and binary files

    https://en.wikipedia.org/wiki/Text_file https://zh.wikipedia.org/wiki/文本文件

  7. Docker Metasploit Framework

    https://hub.docker.com/r/usertaken/metasploit-framework/ docker pull usertaken/metasploit-framework ...

  8. Java基础知识大全

    本文引用于: http://uule.iteye.com/blog/762949 /; DecimalFormat df = new DecimalFormat("0.00");/ ...

  9. word中插入的代码库设置局部背景色

    https://zhidao.baidu.com/question/1494951482361210539.html

  10. WIN文件放到LINUX中无法CAT过滤的解决方法

    有个WIN文件放到LINUX服务器上处理的时候,由于编码的问题,导致无法过滤,此时需要对文件进行处理 cat file | tr -s "\r" "\n" &g ...