这道题是第一道欧拉回路(混合图求欧拉回路)的题,还算比较顺利地过掉了。
1 定义
欧拉通路 (Euler tour)——通过图中每条边一次且仅一次,并且过每一顶点的通路。
欧拉回路 (Euler circuit)——通过图中每条边一次且仅一次,并且过每一顶点的回路。
欧拉图——存在欧拉回路的图。
2 无向图是否具有欧拉通路或回路的判定
G有欧拉通路的充分必要条件为:G 连通,G中只有两个奇度顶点(它们分别是欧拉通路的两个端点)。
G有欧拉回路(G为欧拉图):G连通,G中均为偶度顶点。
3 有向图是否具有欧拉通路或回路的判定
D有欧拉通路:D连通,除两个顶点外,其余顶点的入度均等于出度,这两个特殊的顶点中,一个顶点的入度比出度大1,另一个顶点的入度比出度小1。
D有欧拉回路(D为欧拉图):D连通,D中所有顶点的入度等于出度。
4 混合图。混合图也就是无向图与有向图的混合,即图中的边既有有向边也有无向边。
5 混合图欧拉回路
混合图欧拉回路用的是网络流。
把该图的无向边随便定向,计算每个点的入度和出度。如果有某个点出入度之差为奇数,那么肯定不存在欧拉回路。因为欧拉回路要求每点入度 = 出度,也就是总度数为偶数,存在奇数度点必不能有欧拉回路。
现在每个点入度和出度之差均为偶数。将这个偶数除以2,得x。即是说,对于每一个点,只要将x条边反向(入>出就是变入,出>入就是变出),就能保证出 = 入。如果每个点都是出 = 入,那么很明显,该图就存在欧拉回路。
现在的问题就变成了:该改变哪些边,可以让每个点出 = 入?构造网络流模型。有向边不能改变方向,直接删掉。开始已定向的无向边,定的是什么向,就把网络构建成什么样,边长容量上限1。另新建s和t。对于入 > 出的点u,连接边(u, t)、容量为x,对于出 > 入的点v,连接边(s, v),容量为x(注意对不同的点x不同。当初由于不小心,在这里错了好几次)。之后,察看是否有满流的分配。有就是能有欧拉回路,没有就是没有。查看流值分配,将所有流量非 0(上限是1,流值不是0就是1)的边反向,就能得到每点入度 = 出度的欧拉图。
由于是满流,所以每个入 > 出的点,都有x条边进来,将这些进来的边反向,OK,入 = 出了。对于出 > 入的点亦然。那么,没和s、t连接的点怎么办?和s连接的条件是出 > 入,和t连接的条件是入 > 出,那么这个既没和s也没和t连接的点,自然早在开始就已经满足入 = 出了。那么在网络流过程中,这些点属于“中间点”。我们知道中间点流量不允许有累积的,这样,进去多少就出来多少,反向之后,自然仍保持平衡。
所以,就这样,混合图欧拉回路问题,解了。
Code
1 #include <stdio.h>
2 #include <string.h>
3 #include <algorithm>
4 #define M(x, n) memset(x, n, sizeof(x))
5 #define rep(i, n) for(int i = 0; i < n; ++i)
6
7 using namespace std;
8
9 const int inf = 0x7fffffff;
10 const int MaxN = 2000;
11
12 struct Edge {
13 int u, v, w;
14 struct Edge *next, *neg;
15 Edge() {}
16 Edge(const int &U, const int &V, const int &W)
17 :u(U), v(V), w(W){}
18 }mem[1<<19];
19
20 Edge *adj[MaxN<<1], *pre[MaxN<<1];
21 int src, dst, mtp;
22 int q[MaxN<<1], qs, qe;
23 int f[MaxN<<1], mark[MaxN<<1], cut[MaxN<<1];
24 int m, s, indeg[MaxN], outdeg[MaxN];
25
26 inline void addedge(const int &u, const int &v, const int &w) {
27 mem[mtp] = Edge(u, v, w);
28 mem[mtp].next = adj[u]; adj[u] = mem + mtp++;
29 mem[mtp] = Edge(v, u, 0);
30 mem[mtp].next = adj[v]; adj[v] = mem + mtp++;
31 adj[u]->neg = adj[v]; adj[v]->neg = adj[u];
32 }
33
34 bool spfa(int src, int dst) {
35 int u, v;
36 M(f, 0); M(mark, 0); M(pre, 0);
37 f[src] = inf; mark[src] = true; pre[src] = NULL;
38 q[0] = src; qs = 0; qe = 1;
39 while(qs != qe) {
40 u = q[qs++]; if(qs == MaxN) qs = 0;
41 for(Edge *p = adj[u]; p; p = p->next) {
42 v = p->v;
43 if(!mark[v] && p->w > 0) { //<<<<<<<<<<<<<<<<<<<<<<<
44 f[v] = min(f[u], p->w);
45 pre[v] = p;
46 mark[v] = true;
47 q[qe++] = v; if(qe == MaxN) qe = 0;
48 }
49 }
50 }
51 if(f[dst] > 0)
52 return true;
53 return false;
54 }
55
56 int MaxFlow() {
57 int flow = 0;
58 while(spfa(src, dst)) {
59 flow += f[dst];
60 Edge *p = pre[dst];
61 for(int u; p; u = p->u, p = pre[u])
62 p->w -= f[dst], p->neg->w += f[dst];
63 }
64 return flow;
65 }
66
67 inline void add(int i, int &flow) {
68 if(outdeg[i] > indeg[i]) {
69 addedge(src, i, (outdeg[i]-indeg[i])/2);
70 flow += (outdeg[i]-indeg[i])/2;
71 }
72 else if(outdeg[i] < indeg[i])
73 addedge(i, dst, (indeg[i]-outdeg[i])/2);
74 }
75
76 int main() {
77 int t;
78 int bufu[MaxN], bufv[MaxN], bufm[MaxN];
79 for(scanf("%d", &t); t--;) {
80 scanf("%d%d", &m, &s);
81 M(indeg, 0); M(outdeg, 0);
82 for(int i = 0; i < s; ++i) {
83 scanf("%d%d%d", bufu+i, bufv+i, bufm+i);
84 outdeg[bufu[i]]++; indeg[bufv[i]]++;
85 }
86 int i;
87 for(i = 1; i <= m; ++i) {
88 if((outdeg[i] - indeg[i] + 1000)&1)
89 break;
90 }
91 if(i <= m) {
92 printf("impossible\n"); continue;
93 }
94 src = 0; dst = m + 1;
95 int Flow = 0;
96 M(adj, 0); mtp = 0;
97 for(int i = 0; i < s; ++i) {
98 if(!bufm[i] && bufu[i] != bufv[i])
99 addedge(bufu[i], bufv[i], 1);
100 }
101 for(int i = 1; i <= m; ++i)
102 add(i, Flow);
103 if(MaxFlow() == Flow)
104 printf("possible\n");
105 else
106 printf("impossible\n");
107 }
108 return 0;
109 }
110