混合图的欧拉回路--最大流

  欧拉回路,就是由一点出发,每一条边走且只走一次(顶点可以走多次)然后回到起点的路径,无向图是欧拉图当且仅当他的所有的顶点点的度为偶数,一个有向图是欧拉图,当且仅当该图所有顶点度数都是0。那么混合图的欧拉判定。。。

  混合图就是一个含有有向边和无向边的图,混合图判欧拉回路时用的是最大流,至于原理。。。。

  转自牛人博客:

  把该图的无向边随便定向,计算每个点的入度和出度。如果有某个点出入度之差为奇数,那么肯定不存在欧拉回路。因为欧拉回路要求每点入度 = 出度,也就是总度数为偶数,存在奇数度点必不能有欧拉回路。 
  好了,现在每个点入度和出度之差均为偶数。那么将这个偶数除以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连接的点,自然早在开始就已经满足入 = 出了。那么在网络流过程中,这些点属于“中间点”。我们知道中间点流量不允许有累积的,这样,进去多少就出来多少,反向之后,自然仍保持平衡。 
所以,就这样,混合图欧拉回路问题,解了。 
  代表性的题目: pku 1637

 

代码
   
     
1 #include < stdio.h >
2 #include < stdlib.h >
3 #include < string .h >
4   #define INF 0xfffffff
5   #define MM 3050
6 #define NN 250
7
8 /* S表示源点,T表示汇点 */
9 int S, T, idx;
10 int map[NN][NN],pre[NN];
11
12 int Min( int a, int b){
13 return a < b ? a : b;
14 }
15
16 typedef struct node{
17 int v, wt;
18 struct node * nxt;
19 }NODE;
20 NODE edg[MM];
21 NODE * link[NN];
22
23 int h[NN]; // 每个点的高度,即所在层的深度,源点为0
24 int que[MM];
25
26 void add( int u, int v, int x, int y){
27 edg[idx].v = v;
28 edg[idx].wt = x;
29 edg[idx].nxt = link[u];
30 link[u] = edg + idx;
31 idx ++ ;
32
33 edg[idx].v = u;
34 edg[idx].wt = y;
35 edg[idx].nxt = link[v];
36 link[v] = edg + idx;
37 idx ++ ;
38 }
39
40 bool bfs()
41 {
42 int u, v, w, tail, head;
43 memset(h, - 1 , sizeof (h));
44 que[ 0 ] = S;
45 h[S] = 0 ;
46 tail = head = 0 ;
47 while (head <= tail){
48 u = que[head ++ ];
49 for (NODE * p = link[u]; p; p = p -> nxt){
50 v = p -> v; w = p -> wt;
51 if (h[v] == - 1 && w > 0 ){
52 h[v] = h[u] + 1 ;
53 que[ ++ tail] = v;
54 }
55 }
56 }
57 return h[T] != - 1 ;
58 }
59
60 int dfs( int u, int flow){
61 if (u == T){
62 return flow;
63 }
64 int tmpf = 0 ;
65 int v, w, f;
66 for (NODE * p = link[u]; p; p = p -> nxt){
67 v = p -> v; w = p -> wt;
68 if (h[v] == h[u] + 1 && w && tmpf < flow && (f = dfs(v, Min(w, flow - tmpf)))){
69 p -> wt -= f;
70 int t = p - edg;
71 if (t % 2 == 0 ) edg[t + 1 ].wt += f;
72 else edg[t - 1 ].wt += f;
73 tmpf += f;
74 }
75 }
76 if (tmpf == 0 ) h[u] = - 1 ;
77 return tmpf;
78 }
79 int dinic()
80 {
81 int ans = 0 ;
82 while (bfs()){
83 ans += dfs(S, INF);
84 }
85 return ans;
86 }
87 void init()
88 {
89 idx = 0 ;
90 for ( int i = S; i <= T; i ++ ) link[i] = 0 ;
91 }
92 int main()
93 {
94 int ncase,m,s,i,x,y,v;
95 int du[NN];
96 scanf ( " %d " , & ncase);
97 while (ncase -- ){
98 scanf ( " %d%d " , & m, & s);
99 S = 0 ; T = m + 1 ; init();
100 // for (i = S; i<= T; i++) link[i] = 0;
101 // memset(map,0,sizeof(map));
102 memset(du, 0 , sizeof (du));
103 for (i = 0 ; i < s; i ++ ){
104 scanf ( " %d%d%d " , & x, & y, & v);
105 if (x != y){
106 du[x] ++ ; du[y] -- ;
107 if (v == 0 ) add(x,y, 1 , 0 );
108 }
109 }
110 bool flag = true ; int sum = 0 ;
111 for (i = 1 ; i <= m; i ++ ){
112 if (du[i] % 2 != 0 ){flag = false ; break ;}
113 du[i] /= 2 ;
114 if (du[i] > 0 ){
115 sum += du[i];
116 add(S,i,du[i], 0 );
117 }
118 else add(i,T, - du[i], 0 );
119 }
120 if (flag == false || sum != dinic()) printf ( " impossible\n " );
121 else printf ( " possible\n " );
122 }
123 return 0 ;
124 }

 

你可能感兴趣的:(最大流)