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 }
时间: 2024-08-04 11:15:47

UVa10735 Euler Circuit (混合图的欧拉回路,最大流)的相关文章

UVA 10735 Euler Circuit 混合图的欧拉回路(最大流,fluery算法)

题意:给一个图,图中有部分是向边,部分是无向边,要求判断是否存在欧拉回路,若存在,输出路径. 分析:欧拉回路的定义是,从某个点出发,每条边经过一次之后恰好回到出发点. 无向边同样只能走一次,只是不限制方向而已,那么这个情况下就不能拆边.不妨先按照所给的start和end的顺序,初步定下该无向边的顺序(若不当,一会再改).那么有个问题,我们需要先判断其是否存在欧拉回路先. 混合图不满足欧拉回路因素有:(1)一个点的度(无论有无向)是奇数的,那么其肯定不能满足出边数等于入边数.(2)有向边的出入度过

poj1637 Sightseeing tour,混合图的欧拉回路问题,最大流解

混合图的欧拉回路问题 题目地址 欧拉回路问题 1 定义 欧拉通路 (Euler tour)--通过图中每条边一次且仅一次,并且过每一顶点的通路. 欧拉回路 (Euler  circuit)--通过图中每条边一次且仅一次,并且过每一顶点的回路. 欧拉图--存在欧拉回路的图.  2 无向图是否具有欧拉通路或回路的判定  G有欧拉通路的充分必要条件为:G 连通,G中只有两个奇度顶点(它们分别是欧拉通路的两个端点). G有欧拉回路(G为欧拉图):G连通,G中均为偶度顶点.  3 有向图是否具有欧拉通路或

POJ 1637 Sightseeing tour(混合图的欧拉回路)

题目链接 建个图,套个模板. #include <cstdio> #include <cstring> #include <iostream> #include <map> #include <algorithm> #include <vector> #include <string> #include <queue> using namespace std; #define INF 0x3ffffff str

bzoj2095: [Poi2010]Bridges(二分+混合图求欧拉回路)

传送门 这篇题解讲的真吼->这里 首先我们可以二分一个答案,然后把所有权值小于这个答案的都加入图中 那么问题就转化为一张混合图(既有有向边又有无向边)中是否存在欧拉回路 首先 无向图存在欧拉回路,当且仅当图的所有顶点度数都为偶数且图连通.        有向图存在欧拉回路,当且仅当图的所有顶点入度等于出度且图连通. 那么我们怎么判断混合图的欧拉回路是否存在呢? 我们把无向边的边随便定向,然后计算每一个点的入度和出度.如果有某一个点的入度和出度之差是奇数,那么肯定不存在欧拉回路. 因为欧拉回路要求

欧拉回路、混合图的欧拉回路

欧拉回路 从一个点开始把图中的边恰好经过一次,再回到出发点,这样的路径就是欧拉回路. 如图就是一个欧拉回路 欧拉回路判定 不过怎么样的图中才存在欧拉回路呢? 欧拉回路分有向图和无向图两种: 有向图: 图中所有点的入度等于出度 无向图: 图中所有点的度数都为偶数 这还是很好理解的,不过你可能要问,怎么知道一个混合图中有没有欧拉回路呢? 混合图的欧拉回路 过程: 先将无向边随意定向 判断每个点的入度和出度是不是同奇偶,不同则无解 用一个超级原点向出度小于入度的点连一条容量为 \({|入度-出度| \

UVa 10735 (混合图的欧拉回路) Euler Circuit

题意: 给出一个图,有的边是有向边,有的是无向边.试找出一条欧拉回路. 分析: 按照往常的思维,遇到混合图,我们一般会把无向边拆成两条方向相反的有向边. 但是在这里却行不通了,因为拆成两条有向边的话,就表示这个边能“在两个相反方向各经过一次”. 而题意是这个边只能经过一次. 假设图中存在欧拉回路,则所有点的出度out(i) 等于 入度in(i) 不妨这样,先将所有的无向边任意定向,对于out(u) > in(u)的点,可以将已经定向的无向边u->v反向为v->u,这样out(u) - i

UVA 10735 混合图的欧拉回路

题意: 判断混合图中是否存在欧拉回路,如果存在欧拉回路,输出路径. 思路: 欧拉回路 存在每条边经过且只经过一次后回到原点的路径 在混合图中存在欧拉回路,需要满足以下条件: 1.把所有无向边任意规定一个方向后,对于每个点,满足 |入度-出度| % 2 == 0 2.按照上面已经规定的方向,利用 无向边 建图(有向边忽略掉),然后对于每个结点u,如果in[u]<out[u], 建边(s, u, |入度-出度| / 2);如果in[u]>out[u], 建边(u, t, |入度-出度| / 2)

混合图的欧拉回路判定

对于有向图和无向图的欧拉回路判定,很容易做到.那对于混合图呢?? 混合图就是图中既存在无向边又存在有向边的图. 至于解法: 转载自这里 把该图的无向边随便定向,计算每个点的入度和出度.如果有某个点出入度之差为奇数,那么肯定不存在欧拉回路.因为欧拉回路要求每点入度 = 出度,也就是总度数为偶数,存在奇数度点必不能有欧拉回路. 好了,现在每个点入度和出度之差均为偶数.那么将这个偶数除以2,得x.也就是说,对于每一个点,只要将x条边改变方向(入>出就是变入,出>入就是变出),就能保证出 = 入.如果

POJ 1637 混合图的欧拉回路判定

题意:一张混合图,判断是否存在欧拉回路. 分析参考: 混合图(既有有向边又有无向边的图)中欧拉环.欧拉路径的判定需要借助网络流! (1)欧拉环的判定:一开始当然是判断原图的基图是否连通,若不连通则一定不存在欧拉环或欧拉路径(不考虑度数为0的点). 其实,难点在于图中的无向边,需要对所有的无向边定向(指定一个方向,使之变为有向边),使整个图变成一个有向欧拉图(或有向半欧拉图).若存在一个定向满足此条件,则原图是欧拉图(或半欧拉图)否则不是.关键就是如何定向? 首先给原图中的每条无向边随便指定一个方