有一个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;
}

最新文章

  1. 详解SQL盲注测试高级技巧
  2. VS 2013编译64位版本QT 4.8.6及使用cmake为依赖QT生成VS项目时Could NOT find Qt4
  3. jvisualvm参数配置
  4. python正则表达式
  5. [LintCode] Paint House II 粉刷房子之二
  6. Java编译过程、c/c++编译过程区别
  7. 浅谈c++ new and delete or new [] and delete []
  8. IIS管理器的快捷方式在哪里?
  9. php循环创建目录
  10. ☀【JS】有效状态机
  11. date命令使用总结【转载】
  12. php非递归无限级分类.
  13. Http Analyzer 数据抓包
  14. Oracle 经常使用命令小结
  15. ECLIPSE IDEA 调音 1
  16. PS-前端切图教程(切jpg图和切png图)
  17. Python 的经典入门书籍有哪些?
  18. Keil提示premature end of file错误 无法生成HEX文件
  19. Oracle处理XML字段时遇到的ORA-31013: XPATH 表达式无效问题
  20. STM32-正弦波可调(50HZ~20KHZ可调、峰峰值0~3.3V可调)

热门文章

  1. C#设计模式学习笔记:(12)代理模式
  2. Maven 仓库、坐标、常用命令
  3. Redis实现访问控制频率
  4. Git 学习文档
  5. 如何获取Session对象中的对象
  6. Linux高性能服务器编程:Linux服务器程序规范
  7. SQL语法学习记录——JOIN
  8. python数据类型(总结篇)
  9. 【Android】java中调用JS的方法
  10. css过渡——实现元素的飞入飞出