Sightseeing tour
Description The city executive board in Lund wants to construct a sightseeing tour by bus in Lund, so that tourists can see every corner of the beautiful city. They want to construct the tour so that every street in the city is visited exactly once. The bus should also start and end at the same junction. As in any city, the streets are either one-way or two-way, traffic rules that must be obeyed by the tour bus. Help the executive board and determine if it's possible to construct a sightseeing tour under these constraints.
Input On the first line of the input is a single positive integer n, telling the number of test scenarios to follow. Each scenario begins with a line containing two positive integers m and s, 1 <= m <= 200,1 <= s <= 1000 being the number of junctions and streets, respectively. The following s lines contain the streets. Each street is described with three integers, xi, yi, and di, 1 <= xi,yi <= m, 0 <= di <= 1, where xi and yi are the junctions connected by a street. If di=1, then the street is a one-way street (going from xi to yi), otherwise it's a two-way street. You may assume that there exists a junction from where all other junctions can be reached.
Output For each scenario, output one line containing the text "possible" or "impossible", whether or not it's possible to construct a sightseeing tour.
Sample Input 4 5 8 2 1 0 1 3 0 4 1 1 1 5 0 5 4 1 3 4 0 4 2 1 2 2 0 4 4 1 2 1 2 3 0 3 4 0 1 4 1 3 3 1 2 0 2 3 0 3 2 0 3 4 1 2 0 2 3 1 1 2 0 3 2 0 Sample Output possible impossible impossible possible Source |
[Submit] [Go Back] [Status] [Discuss]
网络流 —— 混合图的欧拉回路
给出一张既有无向边,也有有向边的混合图,判断是否能找到欧拉回路。注意,无向边只能走一次。
考虑有向图的欧拉回路判定——当且仅当所有点的出度=入度时,有向图存在欧拉回路。
发现混合图中无向边事实上也充当着有向边的作用,只是不知道应该怎样安排它的指向而已。
那我们不妨先假设一下它的方向,这样就可以得到图中所有点的入度和出度。用cnt_i表示i点的出度-入度。
可以判断,如果此时存在一个点的cnt值为奇数,那这张图一定不存在欧拉回路,因为如何更改该点的入度都不可能等于出度。
此时考虑,加入存在一条无向边的假设指向不对,我们进行更改,将其方向反转,造成的影响是cnt_u减小2,而cnt_v增加2。这里的u,v分别指原指向的出点和入点。
那我们可以构造网络流了:从源点向每个cnt>0的点连cnt_i的边,表示有cnt_i富余的流量;每个cnt<0的点向汇点连cnt_i的边,表示有cnt_i的不足流量;每条无向边,从u向v连2的边,表示反向这条边会造成的影响。跑最大流,如果满流,则可以通过适当的无向边反转得到欧拉回路。其中满流的无向边就是需要反转的边,当然这道题没有要求输出方案就是了。
一个容易想到的优化是,既然所有容量都是偶数,何不直接对每个容量除以2,虽然不一定有啥用,但总不会慢吧?
1 #include <cstdio> 2 #include <cstring> 3 4 inline int get_c(void) 5 { 6 static const int siz = 1024; 7 8 static char buf[siz]; 9 static char *head = buf + siz; 10 static char *tail = buf + siz; 11 12 if (head == tail) 13 fread(head = buf, 1, siz, stdin); 14 15 return *head++; 16 } 17 18 inline int get_i(void) 19 { 20 register int ret = 0; 21 register int neg = false; 22 register int bit = get_c(); 23 24 for (; bit < 48; bit = get_c()) 25 if (bit == '-')neg ^= true; 26 27 for (; bit > 47; bit = get_c()) 28 ret = ret * 10 + bit - 48; 29 30 return neg ? -ret : ret; 31 } 32 33 template <class T> 34 inline T min(T a, T b) 35 { 36 return a < b ? a : b; 37 } 38 39 const int inf = 2e9; 40 const int maxn = 500005; 41 42 int n, m; 43 44 struct edge 45 { 46 int u, v, k; 47 }e[maxn]; 48 49 int cnt[maxn]; 50 51 int s, t; 52 53 int edges; 54 int hd[maxn]; 55 int to[maxn]; 56 int nt[maxn]; 57 int fl[maxn]; 58 59 inline void add(int u, int v, int f) 60 { 61 nt[edges] = hd[u]; to[edges] = v; fl[edges] = f; hd[u] = edges++; 62 nt[edges] = hd[v]; to[edges] = u; fl[edges] = 0; hd[v] = edges++; 63 } 64 65 int dep[maxn]; 66 67 inline bool bfs(void) 68 { 69 static int que[maxn]; 70 static int head, tail; 71 72 memset(dep, 0, sizeof(dep)); 73 head = 0, tail = 0; 74 que[tail++] = s; 75 dep[s] = 1; 76 77 while (head != tail) 78 { 79 int u = que[head++], v; 80 81 for (int i = hd[u]; ~i; i = nt[i]) 82 if (!dep[v = to[i]] && fl[i]) 83 dep[que[tail++] = v] = dep[u] + 1; 84 } 85 86 return dep[t]; 87 } 88 89 int dfs(int u, int f) 90 { 91 if (u == t || !f) 92 return f; 93 94 int used = 0, flow, v; 95 96 for (int i = hd[u]; ~i; i = nt[i]) 97 if (dep[v = to[i]] == dep[u] + 1 && fl[i]) 98 { 99 flow = dfs(v, min(fl[i], f - used)); 100 101 used += flow; 102 fl[i] -= flow; 103 fl[i^1] += flow; 104 } 105 106 if (!used) 107 dep[u] = 0; 108 109 return used; 110 } 111 112 inline int maxFlow(void) 113 { 114 int maxFlow = 0, newFlow; 115 116 while (bfs()) 117 while (newFlow = dfs(s, inf)) 118 maxFlow += newFlow; 119 120 return maxFlow; 121 } 122 123 signed main(void) 124 { 125 for (int cas = get_i(); cas--; ) 126 { 127 n = get_i(); 128 m = get_i(); 129 130 memset(hd, -1, sizeof(hd)); 131 memset(cnt, 0, sizeof(cnt)); 132 133 for (int i = 1; i <= m; ++i) 134 { 135 e[i].u = get_i(); 136 e[i].v = get_i(); 137 e[i].k = get_i(); 138 139 ++cnt[e[i].u]; 140 --cnt[e[i].v]; 141 } 142 143 bool flag = false; 144 145 for (int i = 1; i <= n && !flag; ++i) 146 if (cnt[i] & 1)flag = true; 147 148 if (flag) 149 puts("impossible"); 150 else 151 { 152 s = 0, t = n + 1; 153 154 for (int i = 1; i <= m; ++i) 155 if (!e[i].k) 156 add(e[i].u, e[i].v, 1); 157 158 for (int i = 1; i <= n; ++i) 159 if (cnt[i]) 160 { 161 if (cnt[i] > 0) 162 add(s, i, +cnt[i] / 2); 163 else 164 add(i, t, -cnt[i] / 2); 165 } 166 167 int sum = 0; 168 169 for (int i = 1; i <= n; ++i) 170 if (cnt[i] > 0) 171 sum += cnt[i] >> 1; 172 173 if (sum == maxFlow()) 174 puts("possible"); 175 else 176 puts("impossible"); 177 } 178 } 179 }
@Author: YouSiki