BZOJ2668 [cqoi2012]交换棋子 【费用流】
题目链接
题解
容易想到由\(S\)向初始的黑点连边,由终态的黑点向\(T\)连边,然后相邻的点间连边
但是这样满足不了交换次数的限制,也无法计算答案
考虑如何满足一个点的交换次数限制
当然是拆点
但是一个位置被经过时会被交换两次,而终点和起点都只交换了一次
那么我们就拆成三个点\(left\),\(mid\),\(right\),分别管理入,中介,出
它们之间顺次两边,费用为\(1\)
流量将限制\(lim\)拆开,当\(lim\)为奇数时要考虑给哪一边:
如果该点一开始是黑点,终态是白点,那么这个点出边一定比入边多
如果一开始是白点,终态是黑点,那么一定要入边多一点
否则一样多
有一些要注意的地方:
①要判黑白起始是否相同
②相邻不止是四个方向
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<map>
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define mp(a,b) make_pair<int,int>(a,b)
#define cls(s) memset(s,0,sizeof(s))
#define cp pair<int,int>
#define LL long long int
using namespace std;
const int maxn = 2005,maxm = 100005,INF = 1000000000;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
return out * flag;
}
int h[maxn],ne = 1;
struct EDGE{int to,nxt,f,w;}ed[maxm];
inline void build(int u,int v,int f,int w){
ed[++ne] = (EDGE){v,h[u],f,w}; h[u] = ne;
ed[++ne] = (EDGE){u,h[v],0,-w}; h[v] = ne;
}
int d[maxn],minf[maxn],vis[maxn],p[maxn],S,T;
int q[maxn * 10],head,tail;
int mincost(){
int flow = 0,cost = 0,u;
while (true){
for (int i = S; i <= T; i++) vis[i] = 0,d[i] = minf[i] = INF;
d[S] = 0; q[head = tail = 0] = S;
while (head <= tail){
u = q[head++];
vis[u] = false;
Redge(u) if (ed[k].f && d[u] + ed[k].w < d[to = ed[k].to]){
d[to] = d[u] + ed[k].w; p[to] = k; minf[to] = min(ed[k].f,minf[u]);
if (!vis[to]) q[++tail] = to,vis[to] = true;
}
}
if (d[T] == INF) break;
flow += minf[T]; cost += d[T] * minf[T];
u = T;
while (u != S){
ed[p[u]].f -= minf[T];
ed[p[u] ^ 1].f += minf[T];
u = ed[p[u] ^ 1].to;
}
}
return cost;
}
char ss[22][22],st[22][22],lim[22][22];
int n,m,id[22][22],X[8] = {0,0,-1,1,-1,-1,1,1},Y[8] = {-1,1,0,0,-1,1,-1,1},cnta,cntb;
int main(){
n = read(); m = read();
REP(i,n) REP(j,m) id[i][j] = (i - 1) * m + j;
REP(i,n) scanf("%s",ss[i] + 1);
REP(i,n) scanf("%s",st[i] + 1);
REP(i,n) scanf("%s",lim[i] + 1);
int E = n * m,x,nx,ny; S = 0; T = 3 * E + 1;
REP(i,n) REP(j,m){
x = lim[i][j] - '0';
if (ss[i][j] == '1' && st[i][j] == '0'){
cnta++;
build(S,id[i][j],1,0);
build(id[i][j] + E,id[i][j],x / 2,1);
build(id[i][j],id[i][j] + 2 * E,(x + 1) / 2,1);
}
else if (ss[i][j] == '0' && st[i][j] == '1'){
cntb++;
build(id[i][j],T,1,0);
build(id[i][j] + E,id[i][j],(x + 1) / 2,1);
build(id[i][j],id[i][j] + 2 * E,x / 2,1);
}
else {
build(id[i][j] + E,id[i][j],x / 2,1);
build(id[i][j],id[i][j] + 2 * E,x / 2,1);
}
for (int k = 0; k < 8; k++){
nx = i + X[k];
ny = j + Y[k];
if (nx < 1 || ny < 1 || nx > n || ny > m) continue;
build(id[i][j] + 2 * E,id[nx][ny] + E,INF,0);
}
}
if (cnta != cntb) puts("-1");
else{
int ans = mincost();
Redge(S) if (ed[k].f){puts("-1"); return 0;}
printf("%d\n",ans / 2);
}
return 0;
}
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]交换棋子(费用流)
题目描述 有一个n行m列的黑白棋盘,你每次可以交换两个相邻格子(相邻是指有公共边或公共顶点)中的棋子,最终达到目标状态.要求第i行第j列的格子只能参与mi,j次交换. 输入输出格式 输入格式: 第一行 ...
- [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 ...
随机推荐
- redis 问题记录
摘抄来自:https://zhuoroger.github.io/ 1.slowlog和排队延时 slowlog是排查性能问题关键监控指标.它是记录Redis queries运行时间超时特定阀值的系统 ...
- libevent学习一
常见的异步IO存在的问题: 1.使用 fcntl(fd, F_SETFL, O_NONBLOCK);,为什么在处理上效率不好. a.在没有数据可读写的时候,循环会不停执行,浪费掉大部分 ...
- ReadyAPI教程和示例(一)
声明:如果你想转载,请标明本篇博客的链接,请多多尊重原创,谢谢! 本篇使用的 ReadyAPI版本是2.5.0 通过下图你可以快速浏览一下主要的ReadyAPI中SoapUI功能: 一.创建一个功 ...
- 使用unittest里面的discover()方法组织测试用例
import osimport unittest directory = os.getcwd()# 测试用例的目录organize = unittest.defaultTestLoader.disco ...
- 第四篇 与Flask相关的插件(flask-session、wtforms)
公司中使用SQL的种方式: 1. 写Django:ORM(关系对象映射), 2. 写Flask和其他:有两种方式: (1) 原生SQL:使用原生SQL有两种选择: A. pymysql (python ...
- NGUI制作流光效果
效果展示: 技巧: 1.勾选UIPanel下的Normal启用UI的法线贴图,并建立带有法线贴图的UI对象(此处用NGUI自带的Reflector.Atlas中的图作为UI). 2.建立点光源并为其添 ...
- 适合初学者的嵌入式Linux计划
俗话说万事开头难,刚开始的时候,你是否根本就不知如何开始,上网查资料被一堆堆新名词搞的找不到北,去图书馆看书也是找不到方向?又是arm,又是linux,又是uboot头都大了,不知道自己究竟从哪里开始 ...
- Python练习—函数
1.编写函数f(n),实现输入n的值,求出n的阶乘.然后调用此函数计算1! +2!+3!+……10!的结果,输出到屏幕上. def f(n): count = 1; for i in range(1, ...
- 20145214 《Java程序设计》第5周学习总结
20145214 <Java程序设计>第5周学习总结 教材学习内容总结 try和catch Java中所有错误都会被包装为对象,可以尝试try执行程序并捕捉catch代表错误的对象后做一些 ...
- POJ 2229 计数DP
dp[i]代表是数字i的最多组合数如果i是一个奇数,i的任意一个组合都包含1,所以dp[i] = dp[i-1] 如果i是一个偶数,分两种情况讨论,一种是序列中包含1,因此dp[i]=dp[i-1]一 ...