欧拉回路,就是由一点出发,每一条边走且只走一次(顶点可以走多次)然后回到起点的路径,无向图是欧拉图当且仅当他的所有的顶点点的度为偶数,一个有向图是欧拉图,当且仅当该图所有顶点度数都是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 }

 

posted on 2010-08-15 10:37  looker  阅读(1488)  评论(3编辑  收藏  举报