/*混合图的欧拉回路
混合图欧拉回路
原来混合图欧拉回路用的是网络流。
把该图的无向边随便定向,计算每个点的入度和出度。如果有某个点出入度之差为奇数,
那么肯定不存在欧拉回路。因为欧拉回路要求每点入度 = 出度,也就是总度数为偶数,存在奇数度点必不能有欧拉回路。
好了,现在每个点入度和出度之差均为偶数。那么将这个偶数除以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的discuss中的,下面自己总结一下。
混合图的欧拉回路, 既然是欧拉回路首先图必须是连通的:将所有边看成无向边做一遍dfs判断连通性。
要构成欧拉图最后所以得点入度都等于出度,即需要每个点入度和出度之差为偶数,若有两个点为奇数可能有欧拉路,
这时只需要在这两个点之间加一条边,即可转化为欧拉回路问题。
判断完毕后,如果所有点入度和出度差为偶数,构建网络流图,原来图中的有向边,可以删去。
原来的无向边可以任意指定一个方向,之后对所有入度大于出度的点引一条边到汇点,边权为入度与出度差的一半。
对于出度大于入度的点从源点引一条边过来,边权为出度和入度差的一半,最后求最大流,若是漫流,则证明有欧拉回路。
1#include<iostream>
2#include<cstdio>
3#include<cstring>
4using namespace std;
5#define MAXV 30
6#define MAXE 100000
7#define INF 0x1f1f1f1f
8int flag[MAXV],used[MAXV],head[MAXV],q[MAXV],ind[MAXV],outd[MAXV],level[MAXV];
9int src,dest,pe;
10int mp[MAXV][MAXV];
11void dfs(int x)
12{
13 flag[x]=1;
14 for(int i=0;i<26;i++)
15 if(!flag[i]&&mp[x][i])
16 dfs(i);
17}
18struct node
19{
20 int v,next,dup;
21 int cap,f;
22 node(){}
23 node(int _v,int _next,int _dup,int _cap,int _f):v(_v),next(_next),dup(_dup),cap(_cap),f(_f){}
24}Elist[MAXE];
25
26inline void add_edge(int u,int v,int cap,int f=0)
27{
28 Elist[pe]=node(v,head[u],pe+1,cap,f);
29 head[u]=pe++;
30 Elist[pe]=node(u,head[v],pe-1,0,-f);
31 head[v]=pe++;
32}
33bool dinic_bfs()
34{
35 int qs(0),qe(1),p;
36 memset(level,-1,sizeof(level));
37 level[src]=0;
38 q[0]=src;
39 while(qs<qe)
40 {
41 for(p=head[q[qs]];p!=-1;p=Elist[p].next)
42 {
43 if(level[Elist[p].v]==-1&&Elist[p].cap>Elist[p].f)
44 {
45 level[Elist[p].v]=level[q[qs]]+1;
46 q[qe++]=Elist[p].v;
47 }
48 }
49 qs++;
50 }
51 return level[dest]!=-1;
52}
53
54int Dinic(){
55 int sh, cur, u, i, *stack = q, p;
56 int ans(0), m;
57 while(dinic_bfs()){
58 // cout<<"after bfs "<<endl;
59 sh = 1;
60 stack[0] = src;
61 while(sh != -1){
62 cur = stack[sh-1]; //一个点的ID接着一个边的ID
63 if(cur == dest){
64 m = (1<<30);
65 for(i = 1; i < sh; ++i, ++i)
66 if(m > Elist[stack[i]].cap - Elist[stack[i]].f){
67 m = Elist[stack[i]].cap - Elist[stack[i]].f;
68 u = i;
69 }
70 for(i = 1; i < sh; ++i, ++i){
71 Elist[stack[i]].f += m;
72 Elist[Elist[stack[i]].dup].f -= m;
73 }
74 ans += m;
75 sh = u;
76 }
77 else {
78 for(p = head[cur]; p != -1; p = Elist[p].next)
79 if(level[Elist[p].v] == level[cur]+1 &&Elist[p].cap > Elist[p].f){
80 stack[sh++] = p;
81 stack[sh++] = Elist[p].v;
82 break;
83 }
84 if(p == -1){
85 level[cur] = -1;
86 --sh, --sh;
87 }
88 }
89 }
90 }
91 return ans;
92}
93
94int main()
95{
96 int t,test,n,i,f,u,v;
97 scanf("%d",&test);
98 for(t=1;t<=test;t++)
99 {
100 scanf("%d",&n);
101 char str[100];
102 memset(head,-1,sizeof(head));
103 pe=0;
104 memset(mp,0,sizeof(mp));
105 memset(flag,0,sizeof(flag));
106 memset(used,0,sizeof(used));
107 memset(ind,0,sizeof(ind));
108 memset(outd,0,sizeof(outd));
109 src=26;dest=27;
110 for(i=0;i<n;i++)
111 {
112 scanf("%s",str);
113 scanf("%d",&f);
114 u=str[0]-'a';
115 outd[u]++;
116 v=str[strlen(str)-1]-'a';
117 ind[v]++;
118 mp[u][v]=mp[v][u]=1;
119 used[u]=used[v]=1;
120 if(f)
121 add_edge(u,v,1);
122 }
123 printf("Case %d: ",t);
124 for(i=0;i<26;i++)
125 if(used[i])
126 {
127 dfs(i);
128 break;
129 }
130 for(i=0;i<26;i++)
131 if(used[i]&&!flag[i])
132 {
133 printf("Poor boy!\n");
134 break;
135 }
136 if(i!=26) continue;
137 int total,sum;
138 total=sum=0;
139 for(i=0;i<26;i++)
140 if(used[i])
141 {
142 if((ind[i]-outd[i])%2!=0)
143 {
144 total++;
145 if(total==1)
146 u=i;
147 else if(total==2)
148 v=i;
149 }
150 }
151 if(total==1||total>2)
152 {
153 printf("Poor boy!\n");
154 continue;
155 }
156 if(total==2)
157 {
158 ind[u]++;
159 outd[v]++;
160 add_edge(v,u,1);
161 }
162 for(i=0;i<26;i++)
163 {
164 if(outd[i]>ind[i])
165 {
166 add_edge(src,i,(outd[i]-ind[i])/2);
167 sum+=(outd[i]-ind[i])/2;
168 }
169 else if(ind[i]>outd[i])
170 add_edge(i,dest,(ind[i]-outd[i])/2);
171 }
172 int tmp=Dinic();
173 if(tmp==sum)
174 printf("Well done!\n");
175 else
176 printf("Poor boy!\n");
177
178
179 }
180 return 0;
181}
182
183