标签:
Description
Input
Output
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
题意:
给出一张既有单向边又有双向边的图,给其中的双向边定向之后使得图构成欧拉回路,问是否存在可行方案。
分析:
对于无向边,我们不知道方向,就随便定向,然后再想想怎么修改。
定完向之后,求所有点的出度与入度,如果任意一个点出度和入度的差为奇数,那么图将无法构成欧拉回路。
(先假设,一个点的出度和入度分别为out和in,如果出度和入度的差|out-in|为奇数,这时有a条连向这个点的边改变了方向,b条从这个点向外连的边改变了方向,那么它的入度就变为了in-a+b,出度变为了out-b+a,出度和入度的差|out-b+a-in+a-b|=|out-in+2a-2b|还是奇数,所以无论如何将边重定向,图都无法构成欧拉回路。)
对于图中的一个点,如果in>out,则说明需要有(in - out)/2条出边需要改变方向,如果in<out,则说明需要有(out - in)/2条入边需要改变方向。而对于无向边(u,v),定义其方向为u->v,那么它将有可能被改为v->u。
剩下的问题用最大流就能解决,对于每个in>out的节点,从源向这个点连一条流量为(in-out)/2的边,对于每个in<out的点,从这个点向汇连一条流量为(out-in)/2的边。而对于每条被定向为u->v的无向边,从v向u连接一条流量为1的边,这条边被流过则说明(u,v)被改变了方向。
跑一遍最大流,如果最大的流量等于与汇相连的边的流量总和,则说明在将一些边重定向后可以满足所有点出度与入度相等,即可以构成欧拉回路。
代码:
1 #include <cstdio> 2 #include <cstring> 3 4 const int maxn = 300; 5 const int maxm = 3000; 6 7 int et[maxm], ep[maxm], ef[maxm]; 8 int last[maxn], en; 9 int p1, p2, dir; 10 int t, n, m, sta, end, ans, ind[maxn]; 11 12 inline void insert(int from, int to, int flow) 13 { 14 en++; 15 et[en] = to; 16 ef[en] = flow; 17 ep[en] = last[from]; 18 last[from] = en; 19 en++; 20 et[en] = from; 21 ef[en] = 0; 22 ep[en] = last[to]; 23 last[to] = en; 24 } 25 26 inline int min(int a, int b) 27 { 28 return a < b ? a : b; 29 } 30 31 int gap[maxn], dis[maxn], cur[maxn]; 32 33 int sap(int now, int flow) 34 { 35 if (now == end) 36 { 37 return flow; 38 } 39 int ret = 0, tmp; 40 for (int e = cur[now]; e; cur[now] = e = ep[e]) 41 { 42 if (et[e] > 0 && dis[now] == dis[et[e]] + 1) 43 { 44 tmp = sap(et[e], min(flow - ret, ef[e])); 45 ret += tmp; 46 ef[e] -= tmp; 47 ef[e ^ 1] += tmp; 48 if (ret == flow) 49 { 50 return ret; 51 } 52 } 53 } 54 cur[now] = last[now]; 55 if (--gap[dis[now]] <= 0) 56 { 57 dis[sta] = end + 1; 58 } 59 ++gap[++dis[now]]; 60 return ret; 61 } 62 63 int maxflow() 64 { 65 memset(gap, 0, sizeof(gap)); 66 memset(dis, 0, sizeof(dis)); 67 int flow = 0; 68 gap[0] = end; 69 for (int i = 1; i <= end; i++) 70 { 71 cur[i] = last[i]; 72 } 73 while (dis[sta] <= end) 74 { 75 flow += sap(sta, 2147483647); 76 } 77 return flow; 78 } 79 80 int main() 81 { 82 scanf("%d", &t); 83 while (t--) 84 { 85 memset(last, 0, sizeof(last)); 86 memset(ind, 0, sizeof(ind)); 87 en = 1; 88 ans = 0; 89 scanf("%d%d", &n, &m); 90 sta = n + 1; 91 end = sta + 1; 92 for (int i = 0; i < m; i++) 93 { 94 scanf("%d%d%d", &p1, &p2, &dir); 95 ind[p1]--; 96 ind[p2]++; 97 if (!dir) 98 { 99 insert(p2, p1, 1); 100 } 101 } 102 bool flag = 1; 103 for (int i = 1; i <= n; i++) 104 { 105 if (ind[i] % 2 > 0) 106 { 107 flag = 0; 108 break; 109 } 110 if (ind[i] > 0) 111 { 112 insert(sta, i, ind[i] / 2); 113 } 114 if (ind[i] < 0) 115 { 116 insert(i, end, -ind[i] / 2); 117 ans += -ind[i] / 2; 118 } 119 } 120 if (flag == 0) 121 { 122 puts("impossible"); 123 } 124 else 125 { 126 puts(maxflow() == ans ? "possible" : "impossible"); 127 } 128 } 129 }
标签:
原文地址:http://www.cnblogs.com/lightning34/p/4579263.html