传送门

好难的网络流啊,建图真的超难。

如果不告诉我是网络流的话,我估计就会写dfs了。

使用费用流解决本题,设点 $p[i][j]$ 的参与交换的次数上限为 $v[i][j]$ ,以下为建图方式:

  1. 将一个点分成三个点,分别为入点,原点和出点。

  2. 如果开始的图上该位置有棋子,那么从S到该点的原点连一条边权1,费用0的边

  3. 如果结束的图上该位置有棋子,那么从该点的原点到T连一条边权1,费用0的边

  4. 如果该点只在开始的图上出现,那么从该点的入点向原点连一条边权为 $v[i][j]/2$ ,费用为1的边,从该点的原点向出点连一条边权为 $(v[i][j]+1)/2$ ,费用为0的边

  5. 如果该点只在结束的图上出现,那么从该点的入点向原点连一条边权为 $(v[i][j]+1)/2$ ,费用为1的边,从该点的原点向出点连一条边权为 $v[i][j]/2$ ,费用为0的边

  6. 如果以上两点都不符合,那么从该点的入点向原点连一条边权为 $v[i][j]/2$ ,费用为1的边,从该点的原点向出点连一条边权为 $v[i][j]/2$ ,费用为0的边

——by zhouyonglong

我只是题解的搬运工。

最后把每个点的原点和它相邻的点的原点连一条容量为INF,费用为0的边

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 1000001
#define id(i, j, k) ((i - 1) * m + j + (k - 1) * n * m) using namespace std; int n, m, cnt, s, t, ans, sum1, sum2, sum;
int head[N], to[N], nex[N], val[N], cost[N], dis[N], pre[N], path[N];
char s1[21][21], s2[21][21], c[21][21];
const int dx[8] = {1, 1, 0, -1, -1, -1, 0, 1}, dy[8] = {0, 1, 1, 1, 0, -1, -1, -1};
bool vis[N]; inline int read()
{
int x = 0, f = 1;
char ch = getchar();
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
return x * f;
} inline void add(int x, int y, int z, int v)
{
to[cnt] = y;
val[cnt] = z;
cost[cnt] = v;
nex[cnt] = head[x];
head[x] = cnt++;
} inline bool spfa()
{
int i, u, v;
queue <int> q;
memset(vis, 0, sizeof(vis));
memset(pre, -1, sizeof(pre));
memset(dis, 127, sizeof(dis));
q.push(s);
dis[s] = 0;
while(!q.empty())
{
u = q.front();
vis[u] = 0;
q.pop();
for(i = head[u]; ~i; i = nex[i])
{
v = to[i];
if(val[i] && dis[v] > dis[u] + cost[i])
{
dis[v] = dis[u] + cost[i];
pre[v] = u;
path[v] = i;
if(!vis[v])
{
q.push(v);
vis[v] = 1;
}
}
}
}
return pre[t] != -1;
} inline void E()
{
puts("-1"), exit(0);
} int main()
{
int i, j, k, x, y, f;
n = read();
m = read();
s = 0, t = 3 * n * m + 1;
memset(head, -1, sizeof(head));
for(i = 1; i <= n; i++) scanf("%s", s1[i] + 1);
for(i = 1; i <= n; i++) scanf("%s", s2[i] + 1);
for(i = 1; i <= n; i++) scanf("%s", c[i] + 1);
for(i = 1; i <= n; i++)
for(j = 1; j <= m; j++)
{
c[i][j] -= '0';
if(s1[i][j] == '1')
{
sum1++;
add(s, id(i, j, 2), 1, 0);
add(id(i, j, 2), s, 0, 0);
}
if(s2[i][j] == '1')
{
sum2++;
add(id(i, j, 2), t, 1, 0);
add(t, id(i, j, 2), 0, 0);
}
if(s1[i][j] == '1' && s2[i][j] == '0')
{
add(id(i, j, 1), id(i, j, 2), c[i][j] / 2, 1);
add(id(i, j, 2), id(i, j, 1), 0, -1);
add(id(i, j, 2), id(i, j, 3), (c[i][j] + 1) / 2, 0);
add(id(i, j, 3), id(i, j, 2), 0, 0);
}
if(s1[i][j] == '0' && s2[i][j] == '1')
{
add(id(i, j, 1), id(i, j, 2), (c[i][j] + 1) / 2, 1);
add(id(i, j, 2), id(i, j, 1), 0, -1);
add(id(i, j, 2), id(i, j, 3), c[i][j] / 2, 0);
add(id(i, j, 3), id(i, j, 2), 0, 0);
}
if(s1[i][j] == s2[i][j])
{
add(id(i, j, 1), id(i, j, 2), c[i][j] / 2, 1);
add(id(i, j, 2), id(i, j, 1), 0, -1);
add(id(i, j, 2), id(i, j, 3), c[i][j] / 2, 0);
add(id(i, j, 3), id(i, j, 2), 0, 0);
}
for(k = 0; k < 8; k++)
{
x = i + dx[k];
y = j + dy[k];
if(1 <= x && x <= n && 1 <= y && y <= m)
{
add(id(i, j, 3), id(x, y, 1), 1e9, 0);
add(id(x, y, 1), id(i, j, 3), 0, 0);
}
}
}
if(sum1 != sum2) E();
while(spfa())
{
f = 1e9;
for(i = t; i != s; i = pre[i]) f = min(f, val[path[i]]);
sum += f;
ans += dis[t];
for(i = t; i != s; i = pre[i])
{
val[path[i]] -= f;
val[path[i] ^ 1] += f;
}
}
if(sum != sum1) E();
printf("%d\n", ans);
return 0;
}

  

[luoguP3159] [CQOI2012]交换棋子(最小费用最大流)的更多相关文章

  1. BZOJ 2668 [cqoi2012]交换棋子 | 最小费用最大流

    传送门 BZOJ 2668 题解 同时分别限制流入和流出次数,所以把一个点拆成三个:入点in(x).中间点mi(x).出点ou(x). 如果一个格子x在初始状态是黑点,则连(S, mi(x), 1, ...

  2. 【BZOJ-2668】交换棋子 最小费用最大流

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

  3. BZOJ2668:[CQOI2012]交换棋子(费用流)

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

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

    题目链接 BZOJ2668 题解 容易想到由\(S\)向初始的黑点连边,由终态的黑点向\(T\)连边,然后相邻的点间连边 但是这样满足不了交换次数的限制,也无法计算答案 考虑如何满足一个点的交换次数限 ...

  5. [CQOI2012] 交换棋子 (费用流)

    $pdf\space solution$    link #include<iostream> #include<cstring> #include<cstdio> ...

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

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

  7. [cqoi2012]交换棋子

      2668: [cqoi2012]交换棋子 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 1334  Solved: 518[Submit][Stat ...

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

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

  9. [bzoj2668] [洛谷P3159] [cqoi2012] 交换棋子

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

随机推荐

  1. XSS 攻击实验 & 防御方案

    XSS 攻击&防御实验 不要觉得你的网站很安全,实际上每个网站或多或少都存在漏洞,其中xss/csrf是最常见的漏洞,也是最容易被开发者忽略的漏洞,一不小心就要被黑 下面以一个用户列表页面来演 ...

  2. red5 重新分配 ip

    root@hett-OptiPlex-7040:~# ll /usr/local/src/red5/conf/total 144drwxr-xr-x 2 root root  4096  1月  9 ...

  3. FATAL org.apache.hadoop.hdfs.server.datanode.DataNode: Initialization failed for Block pool <registering> (Datanode Uuid unassigned) service to controller/192.168.1.183:9000. Exiting. java.io.IOExcep

    2018-01-09 09:47:38,297 FATAL org.apache.hadoop.hdfs.server.datanode.DataNode: Initialization failed ...

  4. (转)SpringMVC学习(一)——SpringMVC介绍与入门

    http://blog.csdn.net/yerenyuan_pku/article/details/72231272 SpringMVC介绍 SpringMVC是什么? SpringMVC和Stru ...

  5. Objective-C分类 (category)和扩展(Extension) 的区别

    http://blog.csdn.net/yhawaii/article/details/6992094 http://blog.163.com/wangy_0223/blog/static/4501 ...

  6. Django 模型ORM

    from django.db import models # Create your models here. class Book(models.Model): nid = models.AutoF ...

  7. 卷积网络中的通道(Channel)和特征图

    转载自:https://www.jianshu.com/p/bf8749e15566 今天介绍卷积网络中一个很重要的概念,通道(Channel),也有叫特征图(feature map)的. 首先,之前 ...

  8. C++判断两个double类型双精度浮点数是否同号

    看到的一种整数的方法 != y < ) 由此, double x,y; == fabs( ) { } 目前想到的比较合适判断方法. 此外这里还有一种强制转换类型求符号位的方法. /** * Ge ...

  9. VC-基础:关于一些符号的意义

    GUI应用程序:Graphic User Interface图形 用户 接口 SDI:单文档程序(典型的记事本就是SDI) MID:多文档程序(比如VS2008默认就是多文档的)

  10. BOM函数之history对象

    前面的话 history对象保存着用户上网的历史记录,从窗口被打开的那一刻算起.由于安全方面的考虑,开发人员无法得到用户浏览器的URL,但借由用户访问过的页面列表,可以在不知道实际URL的情况下实现后 ...