Destroying The Graph(最小割+拆点)
来源:互联网 发布:java调用scala 编辑:程序博客网 时间:2024/06/10 10:34
Destroying The Graph
Description
Alice assigns two costs to each vertex: Wi+ and Wi-. If Bob removes all arcs incoming into the i-th vertex he pays Wi+ dollars to Alice, and if he removes outgoing arcs he pays Wi- dollars.
Find out what minimal sum Bob needs to remove all arcs from the graph.
Input
Output
Sample Input
3 61 2 34 2 11 21 13 21 23 12 3
Sample Output
531 +2 -2 +
题意:给你一幅有向图, 对于点i删除所有进入该点的边就要支付费用W[i]+(情况1), 删除所有从该点出发的边就要支付费用W[i]-,问删除图中的所有边至少需要多少费用(情况2)。
分析:首先我们根据题意,选点就能删除一些边, 那么这可以看成是“用点去覆盖边”, 这里无非是把边分成了2类,
我们可以把原来的点进行拆点,那么就完完全全等价于“用点去覆盖边",如果支付费用都为1,那么这就是”最小点覆盖集“问题,但这题费用不确定,那么这就是“最小点权覆盖集”问题, 借助二分匹配的思想,我们可以引入“最小割”来解决“最小点权覆盖”问题。
建图:拆点,左点阵为情况2的点, 右点阵为情况1的点,右点阵跟汇点T连流量为W+,左点阵跟源点S连费用为W-,
对于输入的边<u, v> 连边 (u, v+n)费用为无穷大inf。跑一边最大流,求出最小费用。
输出解:最要我们找到一个满足条件的割边集(注意不是所有割边, 因为有一条流已经经过了一条割边,那么下面一条割边就不用选了,这样费用才是最小的),那么就能输出解了。怎么找出割边呢?我们可以在残余网络里走流,如果有一条边是割边,那么之后就流不过去了,不是割边还能继续流,具体实现我们可以从源点S用dfs搜出能走到的点标记vis[] =1,
那么对于边<u,v> 只要 vis[u] = 1 && vis[v] = 0 那就是割边了。
总结:二分匹配的题都可以用最大流来解,在二分图中 有 “最小点覆盖集”和“最打独立集”,如果有了点权,那么就要用最大流(最小割)来解决 “最小点权覆盖集”(最小割)和“最大点权独立集”(最大流)问题。
#include <cstdio>#include <string.h>#include <queue>#include <algorithm>using namespace std;int const MAX = 55000;int const inf = 0x3f3f3f3f;struct Edge{ int to, next; int c;}e[MAX];int head[MAX], tot, s, t;int def[MAX];int n, m;void add(int u, int v, int c){ e[++tot].to = v; e[tot].c = c; e[tot].next = head[u]; head[u] = tot;}int bfs(){ queue<int> q; while(!q.empty()) q.pop(); memset(def, 0, sizeof(def)); def[s] = 1; q.push(s); while(!q.empty()){ int u = q.front(); q.pop(); for(int i = head[u]; i != -1; i = e[i].next){ int v = e[i].to; if(!def[v] && e[i].c > 0){ def[v] = def[u] + 1; q.push(v); } } } return def[t];}int dfs(int u, int mi){ if(u == t) return mi; int tmp; for(int i = head[u]; i != -1; i = e[i].next){ int v = e[i].to; if(e[i].c > 0 && def[v] == (def[u] + 1) && (tmp = dfs(v, min(mi, e[i].c))) > 0 ){ e[i].c -= tmp; e[i+1].c += tmp; return tmp; } } return 0;}int dinic(){ int ans = 0, tmp; while(bfs()){ while(1){ tmp = dfs(0, inf); if(tmp == 0) break; ans += tmp; } } return ans;}int ok[MAX];void DFS(int u){ ok[u] = 1; for(int i = head[u]; i != -1; i = e[i].next){ int v = e[i].to; if(ok[v] == 0 && e[i].c > 0) DFS(v); }}void solve(){ memset(ok, 0, sizeof(ok)); int ans = dinic(); printf("%d\n", ans); int res = 0; DFS(0); for(int i = 1; i <= n; i++){ /*********************************************************************************************************** 巧妙地利用了本题图的特殊性质 A}中不可达的点就是应该执行1操作的点。 残余网络中,左侧不可达的点表示被操作1的流选中了 B}中可达的点就是应该执行2操作的点。 右侧可达的点表示从左侧开始无论如何也没有被流选中,只能留给操作2。 ************************************************************************************************************/ if(!ok[i]) res++; if(ok[i + n]) res++; } printf("%d\n", res); for(int i = 1; i <= n; i++){ if(!ok[i]) printf("%d -\n", i); if(ok[i+n]) printf("%d +\n", i); }}int main(){ int k; while(scanf("%d %d", &n, &m) != EOF){ tot = 0; memset(head, -1, sizeof(head)); s = 0, t = (n * 2) + 1; for(int i = 1; i <= n; i++){ scanf("%d", &k); add(i + n, t, k); add(t, i + n, 0); } for(int i = 1; i <= n; i++){ scanf("%d", &k); add(s, i, k); add(i, s, 0); } for(int i = 1; i <= m; i++){ int u, v; scanf("%d %d", &u, &v); add(u, v + n, inf); add(v + n, u, 0); } solve(); } return 0;}
- Destroying The Graph(最小割+拆点)
- poj 2125 Destroying The Graph(最小割,最小点权覆盖)
- HDU2485 Destroying the bus stations(最小割---点割)
- POJ 2125 Destroying The Graph 二分图最小点权覆盖 最小割
- ZOJ 2429 Destroying The Graph 最小割(最小点权覆盖)
- Destroying The Graph (poj 2125 最小点权覆盖)
- POJ 2125 - Destroying The Graph 构图最小割
- 【BZOJ】【P1322】【Zju2429 Destroying The Graph】【题解】【最小割】
- 【POJ2125】【网络流】【最小割】Destroying The Graph 题解
- POJ 2125 --Destroying The Graph【最小割解决 "最小点权覆盖问题" && 输出解(割边集) && 各种不懂】
- POJ2125 Destroying The Graph(最小割求割点)
- POJ 2125 Destroying The Graph 最小点权覆盖
- zoj 2429 Destroying The Graph 最小点权覆盖
- POJ 2125 Destroying The Graph 最小点权覆盖集
- 【POJ】2125 Destroying The Graph 最小点权覆盖
- poj 2125 Destroying The Graph 最小点权覆盖
- POJ2125 Destroying The Graph 最小点权覆盖
- poj 2125 Destroying The Graph 最小点权覆盖集
- 欢迎使用CSDN-markdown编辑器
- 欧几里得gcd+扩展欧几里得exgcd模板
- C/C++ 图像处理(12)------图像の透视变换
- 输入手机号码自动填充空格 变成3-4-4格式
- Socket —— 发送端与接收端通过 io 交互
- Destroying The Graph(最小割+拆点)
- Android异步任务处理框架AsyncTask源码分析
- win10 microsoft edge能上网,别的浏览器不能上网
- 我新的博客开张啦
- hdu 2012 A计划 BFS
- Linux 匿名管道
- Android Studio 编译报错:Manifest merger failed with multiple errors, see logs
- POJ 2492 A Bug's Life .
- 关于 jquery/touchSwipe.js