UVa10735 Euler Circuit (混合图的欧拉回路,最大流)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UVa10735 Euler Circuit (混合图的欧拉回路,最大流)相关的知识,希望对你有一定的参考价值。
链接:http://vjudge.net/problem/UVA-10735
分析:题目保证底图联通,所以连通性就不用判断了。其次,不能把无向边转成有向边来做,因为本题中无向边只能经过一次,而拆成两条有向边之后变成了“沿着两个相反方向各经过一次”,所以本题不能拆边,而只能给边定向。首先我们给无向边任意定向,比如无向边(u,v),可以将其定向为u->v,于是u的出度和v的入度多1(在保证出入度相等的前提下,后者等价于出度少1),那我们这样随意定向以后反悔了怎么办呢?比如最后u的出度为4,入度为2,因此我们需要有将刚刚任意定向的边反向的机会,我们可以把出度看成是“物品”,先前任意定向的结果把这个“物品”交给了u,最后可能u多了这个“物品”,而和u通过刚才任意定向的边相连的结点v正好需要这个“物品”,所以我们在网络流建图时加上边(u,v,1)表示u能提供1个出度给v,相当于反悔了开始的决定将边反向了,然后哪些点需要扔掉一些出度呢?答案是out(i)>in(i),哪些点需要一些出度呢?答案是out(i)<in(i),将源点S向要扔掉出度的结点连一条容量为(out[i]-in[i])/2的弧,从需要出度的结点向汇点连一条容量为(in[i]-out[i])/2的弧,当且仅当源点连出去的弧全部满载整个图的所有结点出入度相等。(注意:in(i)和out(i)奇偶性不同则问题无解)。
1 #include <cstdio> 2 #include <vector> 3 #include <cstring> 4 #include <queue> 5 #include <algorithm> 6 using namespace std; 7 8 const int maxn = 100 + 5; 9 const int INF = 1000000000; 10 11 struct Edge { 12 int from, to, cap, flow; 13 Edge(int u, int v, int c, int f):from(u), to(v), cap(c), flow(f) {} 14 }; 15 16 struct EdmondsKarp { 17 int n, m; 18 vector<Edge> edges; 19 vector<int> G[maxn]; 20 int a[maxn]; 21 int p[maxn]; 22 23 void init(int n) { 24 for (int i = 0; i < n; i++) G[i].clear(); 25 edges.clear(); 26 } 27 28 void AddEdge(int from, int to, int cap) { 29 edges.push_back(Edge(from, to, cap, 0)); 30 edges.push_back(Edge(to, from, 0, 0)); 31 m = edges.size(); 32 G[from].push_back(m - 2); 33 G[to].push_back(m - 1); 34 } 35 36 int Maxflow(int s, int t) { 37 int flow = 0; 38 for (;;) { 39 memset(a, 0, sizeof(a)); 40 queue<int> Q; 41 Q.push(s); 42 a[s] = INF; 43 while (!Q.empty()) { 44 int x = Q.front(); Q.pop(); 45 for (int i = 0; i < G[x].size(); i++) { 46 Edge& e = edges[G[x][i]]; 47 if (!a[e.to] && e.cap > e.flow) { 48 p[e.to] = G[x][i]; 49 a[e.to] = min(a[x], e.cap - e.flow); 50 Q.push(e.to); 51 } 52 } 53 if (a[t]) break; 54 } 55 if (!a[t]) break; 56 for (int u = t; u != s; u = edges[p[u]].from) { 57 edges[p[u]].flow += a[t]; 58 edges[p[u] ^ 1].flow -= a[t]; 59 } 60 flow += a[t]; 61 } 62 return flow; 63 } 64 }; 65 66 EdmondsKarp g; 67 68 const int maxm = 500 + 5; 69 70 int n, m, u[maxm], v[maxm], directed[maxm], id[maxm], diff[maxn]; 71 72 vector<int> G[maxn]; 73 vector<int> vis[maxn]; 74 vector<int> path; 75 76 void euler(int u) { 77 for (int i = 0; i < G[u].size(); i++) 78 if (!vis[u][i]) { 79 vis[u][i] = 1; 80 euler(G[u][i]); 81 path.push_back(G[u][i] + 1); 82 } 83 } 84 85 void print_answer() { 86 for (int i = 0; i < n; i++) { G[i].clear(); vis[i].clear(); } 87 for (int i = 0; i < m; i++) { 88 bool rev = false; 89 if (!directed[i] && g.edges[id[i]].flow > 0) rev = true; 90 if (!rev) { G[u[i]].push_back(v[i]); vis[u[i]].push_back(0); } 91 else { G[v[i]].push_back(u[i]); vis[v[i]].push_back(0); } 92 } 93 94 path.clear(); 95 euler(0); 96 97 printf("1"); 98 for (int i = path.size()-1; i >= 0; i--) printf(" %d", path[i]); 99 printf("\n"); 100 } 101 102 int main() { 103 int T; 104 scanf("%d", &T); 105 while (T--) { 106 scanf("%d%d", &n, &m); 107 g.init(n + 2); 108 memset(diff, 0, sizeof(diff)); 109 for (int i = 0; i < m; i++) { 110 scanf("%d%d", &u[i], &v[i]); 111 u[i]--; v[i]--; 112 diff[u[i]]++; diff[v[i]]--; 113 char dir; while ((dir = getchar()) == ‘ ‘); 114 directed[i] = (dir == ‘D‘ ? 1 : 0); 115 if (dir == ‘U‘) { id[i] = g.edges.size(); g.AddEdge(u[i], v[i], 1); } 116 } 117 bool ok = true; 118 int s = n, t = n + 1, sum = 0; 119 for (int i = 0; i < n; i++) { 120 if (diff[i] % 2 != 0) { ok = false; break; } 121 if (diff[i] > 0) { g.AddEdge(s, i, diff[i] / 2); sum += diff[i] / 2; } 122 if (diff[i] < 0) { g.AddEdge(i, t, -diff[i] / 2); } 123 } 124 if (!ok || sum != g.Maxflow(s, t)) { printf("No euler circuit exist\n"); } 125 else print_answer(); 126 if (T) putchar(‘\n‘); 127 } 128 return 0; 129 }
以上是关于UVa10735 Euler Circuit (混合图的欧拉回路,最大流)的主要内容,如果未能解决你的问题,请参考以下文章
UVa10735 Euler Circuit (混合图的欧拉回路,最大流)
●POJ 2284 That Nice Euler Circuit
POJ2284 That Nice Euler Circuit (欧拉公式)(计算几何 线段相交问题)
poj2284 That Nice Euler Circuit(欧拉公式)