[CQOI2012] 交换棋子 - 费用流
有一个n行m列的黑白棋盘,你每次可以交换两个相邻格子(相邻是指有公共边或公共顶点)中的棋子,最终达到目标状态。要求第i行第j列的格子只能参与mi,j次交换。
Solution
一个点拆三份,入点,主点,出点
入点向主点连边,主点向出点连边,设该点允许的交换次数为 \(x\) ,根据以下规则确定
若为初态点,则入边限流 \(x/2\),出边限流 \((x+1)/2\)
若为末态点,则入边限流 \((x+1)/2\),出边限流 \(x/2\)
否则,入边限流 \(x/2\),出边限流 \((x+1)/2\)
\(S \to\) 初态点,末态点 \(\to T\),容量 \(1\),费用 \(0\)
八连通相互连边,容量 \(\infty\),费用 \(1\)
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define ll long long
#define reset(x) memset(x,0,sizeof x)
#define reset3f(x) memset(x,0x3f,sizeof x)
const int N = 1005;
namespace flow {
const int N = 100005;
const int M = 1000005;
const int inf = 1e+12;
struct Edge {
int p, c, w, nxt = -1;
} e[N];
int s, t, tans, ans, cost, ind, bus[N], qhead = 0, qtail = -1, qu[M],vis[N], dist[N];
void graph_link(int p, int q, int c, int w) {
e[ind].p = q;
e[ind].c = c;
e[ind].w = w;
e[ind].nxt = bus[p];
bus[p] = ind;
++ind;
}
void make(int p, int q, int c, int w) {
graph_link(p, q, c, w);
graph_link(q, p, 0, -w);
}
int dinic_spfa() {
qhead = 0;
qtail = -1;
memset(vis, 0x00, sizeof vis);
memset(dist, 0x3f, sizeof dist);
vis[s] = 1;
dist[s] = 0;
qu[++qtail] = s;
while (qtail >= qhead) {
int p = qu[qhead++];
vis[p] = 0;
for (int i = bus[p]; i != -1; i = e[i].nxt)
if (dist[e[i].p] > dist[p] + e[i].w && e[i].c > 0) {
dist[e[i].p] = dist[p] + e[i].w;
if (vis[e[i].p] == 0)
vis[e[i].p] = 1, qu[++qtail] = e[i].p;
}
}
return dist[t] < inf;
}
int dinic_dfs(int p, int lim) {
if (p == t)
return lim;
vis[p] = 1;
int ret = 0;
for (int i = bus[p]; i != -1; i = e[i].nxt) {
int q = e[i].p;
if (e[i].c > 0 && dist[q] == dist[p] + e[i].w && vis[q] == 0) {
int res = dinic_dfs(q, min(lim, e[i].c));
cost += res * e[i].w;
e[i].c -= res;
e[i ^ 1].c += res;
ret += res;
lim -= res;
if (lim == 0)
break;
}
}
return ret;
}
void solve(int _s,int _t) {
s=_s; t=_t;
while (dinic_spfa()) {
memset(vis, 0x00, sizeof vis);
ans += dinic_dfs(s, inf);
}
}
void init() {
memset(bus, 0xff, sizeof bus);
}
}
int n,m;
char a[N][N],b[N][N],c[N][N];
int idIn(int i,int j) {
return i*m-m+j+2;
}
int idMid(int i,int j) {
return 2ll + n*m + i*m-m+j;
}
int idOut(int i,int j) {
return 2ll + 2*n*m + i*m-m+j;
}
int check(int i,int j) {
if(i && j && i<=n && j<=m) return 1;
return 0;
}
signed main() {
flow::init();
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i]+1;
for(int i=1;i<=n;i++) cin>>b[i]+1;
for(int i=1;i<=n;i++) cin>>c[i]+1;
int cnt=0,tot=0;
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
if(a[i][j]=='1') cnt++;
if(b[i][j]=='1') tot++;
}
}
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
if(a[i][j]=='1') flow::make(1,idMid(i,j),1,0);
if(b[i][j]=='1') flow::make(idMid(i,j),2,1,0);
int x=c[i][j]-'0';
if(a[i][j]=='1' && b[i][j]=='0') {
flow::make(idIn(i,j),idMid(i,j),x/2,0);
flow::make(idMid(i,j),idOut(i,j),(x+1)/2,0);
}
else if(a[i][j]=='0' && b[i][j]=='1') {
flow::make(idIn(i,j),idMid(i,j),(x+1)/2,0);
flow::make(idMid(i,j),idOut(i,j),x/2,0);
}
else {
flow::make(idIn(i,j),idMid(i,j),x/2,0);
flow::make(idMid(i,j),idOut(i,j),(x+1)/2,0);
}
for(int k=i-1;k<=i+1;k++) {
for(int l=j-1;l<=j+1;l++) {
if(i!=k || j!=l) {
if(check(k,l)) flow::make(idOut(i,j),idIn(k,l),99,1);
}
}
}
}
}
flow::solve(1,2);
if(flow::ans==cnt && cnt==tot) cout<<flow::cost;
else cout<<-1;
}
[CQOI2012] 交换棋子 - 费用流的更多相关文章
- 【BZOJ2668】[cqoi2012]交换棋子 费用流
[BZOJ2668][cqoi2012]交换棋子 Description 有一个n行m列的黑白棋盘,你每次可以交换两个相邻格子(相邻是指有公共边或公共顶点)中的棋子,最终达到目标状态.要求第i行第j列 ...
- BZOJ2668: [cqoi2012]交换棋子(费用流)
Description 有一个n行m列的黑白棋盘,你每次可以交换两个相邻格子(相邻是指有公共边或公共顶点)中的棋子,最终达到目标状态.要求第i行第j列的格子只能参与mi,j次交换. Input 第一行 ...
- BZOJ.2668.[CQOI2012]交换棋子(费用流zkw)
题目链接 首先黑白棋子的交换等价于黑棋子在白格子图上移动,都到达指定位置. 在这假设我们知道这题用网络流做. 那么黑棋到指定位置就是一条路径,考虑怎么用流模拟出这条路径. 我们发现除了路径的起点和终点 ...
- [CQOI2012][bzoj2668] 交换棋子 [费用流]
题面 传送门 思路 抖机灵 一开始看到这题我以为是棋盘模型-_-|| 然而现实是骨感的 后来我尝试使用插头dp来交换,然后又惨死 最后我不得不把目光转向那个总能化腐朽为神奇的算法:网络流 思维 我们要 ...
- [cqoi2012]交换棋子
2668: [cqoi2012]交换棋子 Time Limit: 3 Sec Memory Limit: 128 MBSubmit: 1334 Solved: 518[Submit][Stat ...
- BZOJ 2668: [cqoi2012]交换棋子
2668: [cqoi2012]交换棋子 Time Limit: 3 Sec Memory Limit: 128 MBSubmit: 1112 Solved: 409[Submit][Status ...
- BZOJ2668: [cqoi2012]交换棋子
题解: 可以戳这里:http://www.cnblogs.com/zig-zag/archive/2013/04/21/3033485.html 其实自己yy一下就知道这样建图的正确性了. 感觉太神奇 ...
- BZOJ2668:[CQOI2012]交换棋子(费用流)
题目描述 有一个n行m列的黑白棋盘,你每次可以交换两个相邻格子(相邻是指有公共边或公共顶点)中的棋子,最终达到目标状态.要求第i行第j列的格子只能参与mi,j次交换. 输入输出格式 输入格式: 第一行 ...
- [luoguP3159] [CQOI2012]交换棋子(最小费用最大流)
传送门 好难的网络流啊,建图真的超难. 如果不告诉我是网络流的话,我估计就会写dfs了. 使用费用流解决本题,设点 $p[i][j]$ 的参与交换的次数上限为 $v[i][j]$ ,以下为建图方式: ...
随机推荐
- 下拉菜单的jquery组件封装
首先晒出封装好的dropdown.js (function($){ 'use strict';//使用严格模式 //构造函数形式 function Dropdown(elem,options){ // ...
- workerman离线推送方案
方案一:目前网上比较流行的 方案二:参考腾迅IM
- 为NuGet配置微软官方中国镜像
NuGet微软官方中国镜像地址: https://nuget.cdn.azure.cn/v3/index.json 打开Visual Studio => 工具 => NuGet包管理器 = ...
- BigDecimal精确计算工具类
前言 在实际开发中,遇到例如货币,统计等商业计算的时候,一般需要采用java.math.BigDecimal类来进行精确计算.而这类操作通常都是可预知的,也就是通用的.所以,写了个工具类来方便以后的工 ...
- windows系统中如何删除文件路径过长的文件
Q:通常在使用npm安装包后,路径会变的非常的长,有时候无法手动删除文件: 这个时候可以选中文件点击>添加文件到压缩文件,在弹出出来的框中勾选 压缩后删除原文件,>最后删除压缩包
- android中关于时间的控件
1.日期选择器 <DatePicker android:layout_width="wrap_content" android:layout_height="wra ...
- Java学习之String、StringBuffer、StringBuilder
String 我们知道字符串的分配和其他对象分配一样,是需要消耗高昂的时间和空间的,而且字符串我们使用的非常多.JVM为了提高性能和减少内存的开销,在实例化字符串的时候进行了一些优化:使用字符串常量池 ...
- 大二网课ing学习周记
行稳致远,久久为功! 一个概念套着一个概念哦!码就是关键字,标识属性是也! 1.什么是主码和外码,请举例说明. 关键字也叫码! 首先,在一个关系中,能惟一标识元组的属性or最小属性集称为关系的候选码. ...
- Java 8 Stream Api 中的 peek 操作
1. 前言 我在Java8 Stream API 详细使用指南[1] 中讲述了 [Java 8 Stream API]( "Java 8 Stream API") 中 map 操作 ...
- exp导出含有双引号的表
由于ORACLE默认的表名都是不区分大小写,在创建表时,在数据字典中存储的表名为大写.在有些情况下,如果创建的表在表名上加上双引号("),则创建的表其表名在数据字典中不作转换.比如 SQL& ...