您的位置:首页 > 其它

poj 2125 Destroying The Graph(最小割,最小点权覆盖)

2014-01-16 23:51 435 查看
Destroying The Graph
Time Limit: 2000MSMemory Limit: 65536K
Total Submissions: 6588Accepted: 2081Special Judge
DescriptionAlice and Bob play the following game. First, Alice draws some directed graph with N vertices and M arcs. After that Bob tries to destroy it. In a move he may take any vertex of the graph and remove either all arcs incoming intothis vertex, or all arcs outgoing from this vertex.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.InputInput file describes the graph Alice has drawn. The first line of the input file contains N and M (1 <= N <= 100, 1 <= M <= 5000). The second line contains N integer numbers specifying Wi+. The third line defines Wi-in a similar way. All costs are positive and do not exceed 106 . Each of the following M lines contains two integers describing the corresponding arc of the graph. Graph may contain loops and parallel arcs.OutputOn the first line of the output file print W --- the minimal sum Bob must have to remove all arcs from the graph. On the second line print K --- the number of moves Bob needs to do it. After that print K lines that describe Bob'smoves. Each line must first contain the number of the vertex and then '+' or '-' character, separated by one space. Character '+' means that Bob removes all arcs incoming into the specified vertex and '-' that Bob removes all arcs outgoing from the specifiedvertex.Sample Input
3 6
1 2 3
4 2 1
1 2
1 1
3 2
1 2
3 1
2 3
Sample Output
5
3
1 +
2 -
2 +
题意:给出一个有向图,图中可能存在环和平行边,现在要删除所有的边。每次选择一个点,之后选择删除该点的所有入边或所有出边,若删除所有入边,有一个花费W+,若删除所有出边,则有另一个花费W-。要求删除所有边后花费最小,求最小花费,并输出选择的情况。
思路:对于每个点,有两种选择,那么我们可以将每个点拆点,得i和i+n,源点向所有i连边,流量为W-(割这条边时表示删除该点对应的所有出边),所有i+n向汇点连边,流量为W+(割这条边时表示删除该点对应的所有入边)。然后对于原图中的边(a,b),连边a->b+n,流量为INF,保证这条边不被割掉。最后求最大流即为最小割。
至于输出割边,我们可以对图进行染色,若一条边两端被染了不同的颜色,那么这条边就是割边了。
AC代码:
#include <iostream>#include <cmath>#include <cstdlib>#include <cstring>#include <cstdio>#include <queue>#include <stack>#include <ctime>#include <algorithm>#define ll __int64using namespace std;const int INF = 1000000000;const int maxn = 1000;struct node{int u, v;}ee[maxn * maxn];struct Edge{int u, v, cap, flow, next;}et[maxn * maxn];int low[maxn], pre[maxn], dis[maxn], cnt[maxn], cur[maxn], eh[maxn];int col[maxn], in[maxn], out[maxn];int s, t, num, n, m;void init(){memset(eh, -1, sizeof(eh));num = 0;}void add(int u, int v, int cap, int flow){Edge e = {u, v, cap, flow, eh[u]};et[num] = e;eh[u] = num++;}void addedge(int u, int v, int cap){add(u, v, cap, 0);add(v, u, 0, 0);}int isap(int s, int t, int nv){int u, v, now, flow = 0;memset(dis, 0, sizeof(dis));memset(low, 0, sizeof(low));memset(cnt, 0, sizeof(cnt));for(u = 0; u <= nv; u++) cur[u] = eh[u];low[s] = INF, cnt[0] = nv, u = s;while(dis[s] < nv){for(now = cur[u]; now != -1; now = et[now].next)if(et[now].cap - et[now].flow && dis[u] == dis[v = et[now].v] + 1) break;if(now != -1){cur[u] = pre[v] = now;low[v] = min(low[u], et[now].cap - et[now].flow);u = v;if(u == t){for(; u != s; u = et[pre[u]].u){et[pre[u]].flow += low[t];et[pre[u]^1].flow -= low[t];}flow += low[t];low[s] = INF;}}else{if(--cnt[dis[u]] == 0) break;dis[u] = nv, cur[u] = eh[u];for(now = eh[u]; now != -1; now = et[now].next)if(et[now].cap - et[now].flow && dis[u] > dis[et[now].v] + 1)dis[u] = dis[et[now].v] + 1;cnt[dis[u]]++;if(u != s) u = et[pre[u]].u;}}return flow;}void dfs(int u){col[u] = 1;for(int i = eh[u]; i != -1; i = et[i].next){int v = et[i].v;if(et[i].cap - et[i].flow && !col[v])dfs(v);}}int main(){int a, b;while(~scanf("%d%d", &n, &m)){init();s = 0, t = 2 * n + 1;for(int i = 1; i <= n; i++){scanf("%d", &in[i]);addedge(i + n, t, in[i]);}for(int i = 1; i <= n; i++){scanf("%d", &out[i]);addedge(s, i, out[i]);}while(m--){scanf("%d%d", &a, &b);addedge(a, b + n, INF);}printf("%d\n", isap(s, t, t + 1));int k = 0;dfs(s);for(int i = 1; i <= n; i++){if(!col[i]) k++;if(col[i + n]) k++;}printf("%d\n", k);for(int i = 1; i <= n; i++){if(!col[i]) printf("%d -\n", i);if(col[i + n]) printf("%d +\n", i);}}return 0;}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: