欧拉除了函数,还有个回路----图论之路之欧拉路径欧拉回路 混合图中欧拉回路

首先我们来百度一下,欧拉路径以及回路的定义:

若图G中存在这样一条路径,使得它恰通过G中每条边一次,则称该路径为欧拉路径。若该路径是一个圈,则称为欧拉(Euler)回路。

具有欧拉回路的图称为欧拉图(简称E图)。具有欧拉路径但不具有欧拉回路的图称为半欧拉图。

通俗来说,就是欧拉路径就是图中的每条边经过却只经过一次的路径,而最后回到起点的路径就是欧拉回路。

那给你一个图怎么判断存不存在,欧拉路径或者欧拉回路呢

首先,判断图是不是连通的,这个就很简单了,dfs或者并查集都可以。

然后就是根据定理

欧拉路径的定理

连通的无向图有欧拉路径的充要条件是:

G中奇顶点(连接的边数量为奇数的顶点)的数目等于0或者2。

连通的无向图是欧拉环(存在欧拉回路)的充要条件是:

G中每个顶点的度都是偶数。

欧拉回路的定理

无向图存在欧拉回路的充要条件

一个无向图存在欧拉回路,当且仅当该图所有顶点度数都为偶数,且该图是连通图。

有向图存在欧拉回路的充要条件

一个有向图存在欧拉回路,所有顶点的入度等于出度且该图是连通图。

这四个定理很好理解,无向图的话,因为要把所有边走一遍且只走一边,那对于每个点来说,如果不是起点或者终点的话,那么度数应该是偶数,有一条进边就有一条对于的出边,然后是起点,出边应该多一条,终点应该入边多一条,所以度数是奇数。然后如果没有奇数点的话,那就是任意点都可以作为起点并且能走回它,那就是存在一个回路了,否则就是得两个奇数点,一个起点和一个终点。

有向图的话,就是分为入度出度,道理是一样的,然后我们就可以来做题了

欧拉回路 

HDU - 1878 

 中文题,真模板题,给一个无向图,问存不在在欧拉回路,存在扣1,不存在扣0.

直接并查集判断连通性,只能有一个连通集,然后判断度数,不存在奇数度的点,就ok了。

 1 #include<cstdio>
 2 const int N=1108;
 3 int fa[N],in[N];
 4 int find(int x){
 5     return fa[x]==x ? x : fa[x]=find(fa[x]);
 6 }
 7 void bing(int x,int y){
 8     int fx=find(x),fy=find(y);
 9     if(fx!=fy) fa[fx]=fy;
10     return ;
11 }
12 int main(){
13     int n,m,u,v;
14     while(scanf("%d%d",&n,&m)&&n){
15         for(int i=0;i<=n;i++){
16             fa[i]=i;
17             in[i]=0;
18         }
19         while(m--){
20             scanf("%d%d",&u,&v);
21             in[u]++;
22             in[v]++;
23             bing(u,v);
24         }
25         int flag=1,num=0;
26         for(int i=1;i<=n;i++){
27             fa[i]=find(fa[i]);
28             if(fa[i]==i) num++;
29             if(num>1) flag=0;
30             if(in[i]&1) flag=0;
31             if(!flag) break;
32         }
33         printf("%d\n",flag);
34     }
35     return 0;
36 }
板子敲敲

Ant Trip HDU - 3018 

题意:给一个无向图问,最少分几组能够把所有边走且走一遍?

要把所有边走且只走一遍,其实就是在求一个欧拉路径,但一条路径不一定能把所有边走完,这里要求的就是最少分出多少条欧拉路径。

我们从无向图的欧拉路径定理下手,图中奇顶点(连接的边数量为奇数的顶点)的数目等于0或者2。

那我们先用并查集判断有多少个连通集,然后对于每个连通集,如果它没有奇度点的话,那么一条欧拉路径就能把它的边走完,那如果它的奇度点的个数为x的话,每2个奇度点就能走一条欧拉路径,所以最少就需要(x+1)/2条。

 1 #include<cstdio>
 2 const int N=100118;
 3 int fa[N],in[N],num[N];
 4 int find(int x){
 5     return fa[x]==x ? x : fa[x]=find(fa[x]);
 6 }
 7 void bing(int x,int y){
 8     int fx=find(x),fy=find(y);
 9     if(fx!=fy) fa[fx]=fy;
10     return ;
11 }
12 int main(){
13     int n,m,u,v;
14     while(~scanf("%d%d",&n,&m)){
15         for(int i=0;i<=n;i++){
16             fa[i]=i;
17             in[i]=0;
18             num[i]=0;
19         }
20         while(m--){
21             scanf("%d%d",&u,&v);
22             in[u]++;
23             in[v]++;
24             bing(u,v);
25         }
26         for(int i=1;i<=n;i++){
27             fa[i]=find(fa[i]);
28             if(in[i]&1) num[fa[i]]++;
29         }
30         int ans=0;
31         for(int i=1;i<=n;i++){
32             if(fa[i]!=i) continue;
33             if(!num[i]&&in[i]) ans++;
34             else if(num[i]) ans+=(num[i]+1)/2;
35         }
36         printf("%d\n",ans);
37     }
38     return 0;
39 }
几笔画

Play on Words UVA - 10129 

题意:给两个单词,如果其中一个的最后一个单词等于另外一个的第一个单词的话,那就可以把它们串起来,问能不能把所有单词串起来。

单纯看每个单词的话,那就是得在每两个能串的单词之间连一条边,1e5个单词,这样很明显直接会T,我们想一下,如果一个单词能和其他单词串起来,那不就是它首字母的入度+1或者尾字母的出度+1,然后每个单词其实就是它首字母和尾字母的一条有向边。

这样把所有单词串起来,就是问有向图有没有欧拉路径,我们根据定理判断就ok了。

 1 #include<cstdio>
 2 #include<cstring>
 3 int in[28],out[28],fa[28];
 4 int find(int x){
 5     return fa[x]==x ? x : fa[x]=find(fa[x]);
 6 }
 7 void bing(int x,int y){
 8     int fx=find(x),fy=find(y);
 9     if(fx!=fy) fa[fx]=fy;
10     return ;
11 }
12 char s[1010];
13 int main(){
14     int t,n,lens;
15     scanf("%d",&t);
16     while(t--){
17         scanf("%d",&n);
18         for(int i=0;i<=26;i++){
19             fa[i]=i;
20             in[i]=out[i]=0;
21         }
22         for(int i=0;i<n;i++){
23             scanf("%s",s);
24             lens=strlen(s);
25             in[s[0]-'a']++;
26             out[s[lens-1]-'a']++;
27             bing(s[0]-'a',s[lens-1]-'a');
28         }
29         int flag=1,num1=0,num2=0,num3=0;
30         for(int i=0;i<26;i++){
31             if(in[i]-out[i]==1) num1++;
32             else if(out[i]-in[i]==1) num2++;
33             else if(in[i]!=out[i]) flag=0;
34             if(find(fa[i])==i&&(in[i]||out[i])) num3++;
35             if(num1>1||num2>1||num3>1) flag=0;
36             if(!flag) break;
37         }
38     //    printf("%d %d %d %d\n",flag,num1,num2,num3);
39         if(flag&&num1==num2) printf("Ordering is possible.\n");
40         else printf("The door cannot be opened.\n");
41     }
42     return 0;
43 }
有向的哦

知道怎么判定有没有欧拉路径或者欧拉回路了,那怎么求欧拉路径或者欧拉回路呢?

两个方法,套圈(暴搜)法或者fleury算法。

首先是套圈法,先上代码。

 1 void dfs(int u){
 2     for(int i=1;i<=n;i++){
 3         if(ok[u][i]){
 4             ok[u][i]--;
 5             ok[i][u]--;
 6             dfs(i);
 7         }
 8     }
 9     ans[cnt++]=u;
10 }
欧拉魔力套圈圈

什么意思呢,从一个点出发,能走到哪个点我们就走到哪个点,并且把这条边删除掉,直到这个点走不到其他点了,我们就把它记录下来,然后再把记录点逆序输出。

为什么呢?首先我们先判断有没有欧拉路径或者欧拉回路,有的话那肯定是能走出来的。

然后起点,对于欧拉回路的话,任意点可以作为起点,而欧拉路径的话我们以一个奇度点为起点。从起点出发走,当一个点已经无边可走了,那说明它是当前一个终点或是一个圈的起点。

我们来模拟一下。

第一个图这个1到2到3没路了,这时候很明显3是终点了,开始回溯。

第二图的话,3到2到1到3到4到6到5到4,这样的话4是终点,开始回溯是能走出一条欧拉路径,但我们不可能限定3一定先走到2,可能的是3先走到4。

这时候就是,3走到4,4到6,6到5,5到4,没有路了,把4记录下来,然后回到5,也没路了,再记录下来,接下来6,4,也是一样,直到3,3还能到1,那我们继续走3,1,2,到3没路了,回溯。

欧拉路径我们把逆序把记录的点输出就是3,2,1,3,4,6,5,4,也就是3,2,1,3这个圈再套上了4,6,5,4这个圈。

套圈法的意思其实就是,因为欧拉路径要么一个点同时做起点和终点(回路),或者一个做起点,一个做终点,那么当走到一个点不能再走时,很明显它就是当前的一个终点了,我们就开始回溯,但有可能的就是我们中途走了‘’桥”,如上面的3-4,所以回溯时有点还能继续往下走我们就让它先走,然后再走“桥”。

这样其实就是如果只有一个圈,那就是直接走到终点回溯,多个圈的话,就是先走了圈,然后再走“桥”,把它跟其他桥套起来。

实现上其实就是像上面代码写的,一个点能走到那个点就走,同时把走的这条边删除(注意无向边和有向边),直到一个点无边可走,记录下来,回溯,也就是个dfs过程。

然后fleury算法的话,直接引用guomutian911的博客Fleury (弗罗莱) 算法通俗解释

网上也很多这个算法的代码以及解释,我就不多重复了,从代码量和运行时间来说,我觉得套圈法是更优的,然后直接来上题。

洛谷p2731

中文题,意思就是给定了连通并且保证能有解的无向图,要按字典序最小输出无向图的欧拉路径。

就先判断有没有奇度点,有的话以最小那个为起点,否则以1为起点,然后就是直接dfs了。cur的话是类似最大流里面的一个当前弧优化,不懂没关系。

 1 #include<cstdio>
 2 const int N=520;
 3 int n,cnt,in[N],cur[N],ok[N][N],ans[N*10];
 4 void dfs(int u){
 5     for(int &i=cur[u];i<=500;i++){
 6         if(ok[u][i]){
 7             ok[u][i]--;
 8             ok[i][u]--;
 9             dfs(i);
10         }
11     }
12     ans[cnt++]=u;
13 }
14 int main(){
15     int u,v;
16     while(~scanf("%d",&n)){
17         for(int i=1;i<=500;i++){
18             in[i]=0;
19             cur[i]=1;
20             for(int j=1;j<=500;j++)
21                 ok[i][j]=0;
22         }
23         for(int i=0;i<n;i++){
24             scanf("%d%d",&u,&v);
25             in[u]++;
26             in[v]++;
27             ok[u][v]++;
28             ok[v][u]++;
29         }
30         int beg=1;
31         for(int i=1;i<=500;i++) if(in[i]&1){
32             beg=i;
33             break;
34         }
35         cnt=0;
36         dfs(beg);
37         for(int i=cnt-1;i>=0;i--) printf("%d\n",ans[i]);
38     }
39     return 0;
40 }
模板模板
 1 #include<cstdio>
 2 const int N=520;
 3 int n,cnt,sn,in[N],ok[N][N],sta[N*10],ans[N*10],cur[N];
 4 void dfs(int u){
 5     sta[++sn]=u;
 6     for(int &i=cur[u];i<=500;i++){
 7         if(ok[u][i]){
 8             ok[u][i]--;
 9             ok[i][u]--;
10             dfs(i);
11             break;
12         }
13     }
14 }
15 void fleury(int beg){
16     sn=cnt=0;
17     sta[++sn]=beg;
18     int u,flag;
19     while(sn){
20         flag=0;
21         u=sta[sn];
22         for(int &i=cur[u];i<=500;i++){
23             if(ok[u][i]){
24                 flag=1;
25                 break;
26             }
27         }
28         if(!flag) ans[cnt++]=sta[sn--];
29         else dfs(sta[sn--]);
30     }
31     return ;
32 }
33 int main(){
34     int u,v;
35     while(~scanf("%d",&n)){
36         for(int i=1;i<=500;i++){
37             in[i]=0;
38             for(int j=1;j<=500;j++)
39                 ok[i][j]=0;
40         }
41         for(int i=0;i<n;i++){
42             scanf("%d%d",&u,&v);
43             in[u]++;
44             in[v]++;
45             ok[u][v]++;
46             ok[v][u]++;  
47         }
48         int beg=1;
49         for(int i=1;i<=500;i++) if(in[i]&1){
50             beg=i;
51             break;
52         }
53         fleury(beg);
54         for(int i=cnt-1;i>=0;i--) printf("%d\n",ans[i]);
55     }
56     return 0;
57 }
fleury模板

HZNUOJ Little Sub and Traveling

题意: 一个数x,下一步可以走到,x*2%n或者(x*2+1)%n,给你一个n,要你找一条从0开始,然后0~n-1的数走且只走过一次最终回到0的字典序最大的路径。

看似是每个点只走过一次,是找一个哈密顿回路,其实要找的还是一个欧拉回路。

首先n是奇数,没有答案输出-1,这个暴力打表也可以看出来,那为什么呢,因为可以到0的点只有n/2这个数,这个数还有n是奇数的话,n-1这个数也是只能由n/2这个数走到,那n/2不可能走到其中一个之后又回到它走到另外一个,所以无解。

然后n是偶数的话,我们看x(<=n/2)可以走到,x*2%n以及(x*2+1)%n,而x+n/2可以走到 (x*2+n)%n (x*2+n+1)%n,也就是x跟x+n/2的下一步是一样的话,如果我们把它们两个看成一个整体的话,也就是剩下n/2个点,然后每个点两个入度,两个出度,也就是求一个欧拉回路了。

比如n等于8的时候就像下图这样,所以直接套圈走起。

 1 #include<cstdio>
 2 int n,cnt,vis[10118],ans[10118];
 3 void dfs(int x){
 4     int x1=(x*2+1)%n,x2=x*2%n;
 5     if(!vis[x1]){
 6         vis[x1]=1;
 7         dfs(x1);
 8     }
 9     if(!vis[x2]){
10         vis[x2]=1;
11         dfs(x2);
12     }
13     ans[cnt++]=x;
14     return ;
15 }
16 int main(){
17     while(~scanf("%d",&n)){
18         if(n&1) printf("-1\n");
19         else{
20             for(int i=0;i<n;i++) vis[i]=0;
21             cnt=0;
22             dfs(0);
23             for(int i=cnt-1;i>=0;i--) printf("%d%c",ans[i]," \n"[i==0]);
24         }
25     }
26     return 0;
27 }
投入欧拉的怀抱

UOJ117欧拉回路

中文题,无敌大整合,给你无向或者有向边,问有没有欧拉回路,没有就NO,有的话就YES然后输出任意答案。

判断连通,然后用定理判断,最后套圈法,就这样一气呵成,注意的是这里要输出的是边的编号,所以记录的是边不是点,还有就是这题不用当前弧优化会超时,不知道是什么的,可以去了解一下。

 1 #include<cstdio>
 2 const int N=101108,M=201108;
 3 struct Side{
 4     int v,ne,ok,id;
 5 }S[M<<1];
 6 int t,n,m,sn,cnt,head[N],cur[N],in[N],out[N],fa[N],ans[M<<1];
 7 void init(){
 8     sn=0;
 9     for(int i=1;i<=n;i++){
10         fa[i]=i;
11         head[i]=-1;
12         in[i]=out[i]=0;
13     }
14 }
15 void add(int u,int v,int id){
16     S[sn].ok=1;
17     S[sn].id=id;
18     S[sn].v=v;
19     S[sn].ne=head[u];
20     head[u]=sn++;
21 }
22 int find(int x){
23     return fa[x]==x ? x : fa[x]=find(fa[x]); 
24 }
25 void bing(int x,int y){
26     int fx=find(x),fy=find(y);
27     if(fx!=fy) fa[fx]=fy;
28     return ;
29 }
30 void dfs(int u){
31     for(int &i=cur[u];~i;i=S[i].ne){
32         if(S[i].ok){
33             S[i].ok=0;
34             int temp=i;
35             if(t==1) S[i^1].ok=0;
36             dfs(S[i].v);
37             ans[cnt++]=S[temp].id;
38             if(i==-1) break;
39         }
40     }
41 }
42 int main(){
43     int u,v;
44     while(~scanf("%d",&t)){
45         scanf("%d%d",&n,&m);
46         init();
47         for(int i=1;i<=m;i++){
48             scanf("%d%d",&u,&v);
49             bing(u,v);
50             if(t==1){
51                 in[u]++;
52                 in[v]++;
53                 add(u,v,i);
54                 add(v,u,-i);
55             }else{
56                 in[v]++;
57                 out[u]++;
58                 add(u,v,i);
59             }
60         }
61         int beg=1,flag=1,num=0;
62         for(int i=1;i<=n;i++){
63             cur[i]=head[i];
64             if(fa[i]==i&&in[i]) num++;
65             if(t==1){
66                 if(in[i]&1) flag=0;
67                 else if(in[i]) beg=i;
68             }else{
69                 if(in[i]!=out[i]) flag=0;
70                 else if(in[i]) beg=i;
71             }
72             if(!flag||num>1) break;
73         }
74         if(flag&&num<=1){
75             printf("YES\n");
76             if(num){
77                 cnt=0;
78                 dfs(beg);
79                 for(int i=cnt-1;i>=0;i--) printf("%d%c",ans[i]," \n"[i==0]);
80             }
81         }else printf("NO\n");
82     }
83     return 0;
84 }
学会这题就完全OK了

 那如果是一个混合图的话,我们怎么办呢?

这涉及到最大流,不会最大流的可以去学一下。

具体步骤的话,直接引用Adela混合图中欧拉回路我就不重复了,直接说为什么

想法其实就是,因为有向边的方向已经固定了,这没法更改,我们这样就是看能不能给无向边定一个方向,然后把整个图成为有向图,然后就是有向图的判定了。

而这个给定方向就是就是通过最大流的调整了,有向边就是统计入度出度,对于每条a与b之间无向边,我们先假定一个a->b的方向,然后统计出度入度,以及建一条流量为1从a到b的边,说明a到b之间有一条可以反向的无向边。

如果存在出度与入度奇偶性不同的点的话,肯定就不存在欧拉回路了,因为改变一条无向边的方向,对于两边的点来说,也就是出度-1,入度+1,或者出度+1,入度-1,奇偶性变化是一样的,如果一开始奇偶性就不同的话,肯定没法使得出度等于入度。

然后对于每个出度大于入度的点,我们把它与源点连一条流量为(出度-入度)/2的边,(出度-入度)/2其实就是需要改变多少条连到它上面的无向边,使得它出度等于入度。而对于入度大于出度的点,则是与汇点连一条流量为(入度-出度)/2的边。

所以最终能不能有欧拉回路,也就是看能不能满流,让每个点都满足出度等于入度的要求。

而欧拉路径的话,就是最多只能有两个出度与入度奇偶性不同的点,也就是终点和起点,然后我们找到这两个点,给它们连一条无向边,那处理就跟欧拉回路的一样了。

至于路径的输出,我们就看之前流量为1的那些边,如果流量变为0了,说明反向了,否则就是我们原定的方向,就用这些新的有向边和原来的有向边,然后有向图的欧拉回路就ok了。

直接挂三道题,题意就不说了,练一下英语吧~~~~~~~~

HDU3472  POJ1637  UVA10735

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<queue>
  4 #include<algorithm>
  5 using namespace std;
  6 const int N=36,M=2118,inf=1e9+7;
  7 struct Node{
  8     int v,ne,w;
  9 }S[M<<1];
 10 char s[N];
 11 int sn,sb,se,head[N],cur[N],dep[N];
 12 int n,in[N],out[N],fa[N];
 13 void init(){
 14     sn=0;
 15     sb=26,se=27;
 16     for(int i=0;i<=se;i++){
 17         fa[i]=i;
 18         head[i]=-1;
 19         in[i]=out[i]=0;
 20     }
 21 }
 22 int find(int x){
 23     return fa[x]==x ? x : fa[x]=find(fa[x]); 
 24 }
 25 void bing(int x,int y){
 26     int fx=find(x),fy=find(y);
 27     if(fx!=fy) fa[fx]=fy;
 28     return ;
 29 }
 30 void add(int u,int v,int w){
 31     S[sn].w=w;
 32     S[sn].v=v;
 33     S[sn].ne=head[u];
 34     head[u]=sn++;
 35 }
 36 void addE(int u,int v,int w){
 37     add(u,v,w);
 38     add(v,u,0);
 39 }
 40 bool bfs(){
 41     for(int i=0;i<=se;i++) dep[i]=0;
 42     dep[sb]=1;
 43     queue<int> q;
 44     q.push(sb); 
 45     int u,v;
 46     while(!q.empty()){
 47         u=q.front();
 48         q.pop();
 49         for(int i=head[u];~i;i=S[i].ne){
 50             v=S[i].v;
 51             if(S[i].w>0&&!dep[v]){
 52                 dep[v]=dep[u]+1;
 53                 if(v==se) return true;
 54                 q.push(v);
 55             }
 56         }
 57     }
 58     return false;
 59 }
 60 int dfs(int u,int minf){
 61     if(u==se||!minf) return minf;
 62     int v,flow;
 63     for(int &i=cur[u];~i;i=S[i].ne){
 64         v=S[i].v;
 65         if(S[i].w>0&&dep[v]==dep[u]+1){
 66             flow=dfs(v,min(minf,S[i].w));
 67             if(flow){
 68                 S[i].w-=flow;
 69                 S[i^1].w+=flow;
 70                 return flow;
 71             }
 72         }
 73     }
 74     return 0;
 75 }
 76 int dinic(){
 77     int maxf=0,flow;
 78     while(bfs()){
 79         for(int i=0;i<=se;i++) cur[i]=head[i];
 80         while(flow=dfs(sb,inf)) maxf+=flow;
 81     }
 82     return maxf;
 83 }
 84 int main(){
 85     int t=1,T,u,v,op,lens;
 86     scanf("%d",&T);
 87     while(t<=T){
 88         init();
 89         scanf("%d",&n);
 90         for(int i=0;i<n;i++){
 91             scanf("%s%d",s,&op);
 92             lens=strlen(s);
 93             u=s[0]-'a';
 94             v=s[lens-1]-'a';
 95             in[v]++;
 96             out[u]++;
 97             bing(u,v);
 98             if(op) addE(u,v,1);
 99         }
100         int num1=0,num2=0,x1=-1,x2=-1;
101         for(int i=0;i<26;i++){
102             if(fa[i]==i&&(in[i]||out[i])) num1++;
103             if((in[i]-out[i])&1){
104                 num2++;
105                 if(x1==-1) x1=i;
106                 else x2=i;
107             }
108             if(num1>1||num2>2) break;
109         }
110         printf("Case %d: ",t++);
111         if(num1!=1||num2>2||num2==1){
112             printf("Poor boy!\n");
113             continue;
114         }
115         if(num2==2){
116             in[x1]++;
117             out[x2]++;
118             addE(x2,x1,1);
119         }
120         int sum1=0,sum2=0;
121         for(int i=0;i<26;i++){
122             if(in[i]==out[i]) continue;
123             if(in[i]>out[i]){
124                 sum1+=(in[i]-out[i])/2;
125                 addE(i,se,(in[i]-out[i])/2);
126             }
127             else{
128                 sum2+=(out[i]-in[i])/2;
129                 addE(sb,i,(out[i]-in[i])/2);
130             }
131         }
132     //    printf("%d %d %d\n",sum1,sum2,dinic());
133         if(sum1!=sum2||dinic()!=sum1) printf("Poor boy!\n");
134         else printf("Well done!\n");
135     }
136     return 0;
137 }
hdu
  1 #include<cstdio>
  2 #include<algorithm>
  3 using namespace std;
  4 const int N=218,M=2108,inf=1e9+7;
  5 struct Node{
  6     int v,ne,w;
  7 }S[M<<1];
  8 int sn,sb,se,head[N],cur[N],dep[N];
  9 int n,m,in[N],out[N],q[201108];
 10 void init(){
 11     sn=0;
 12     sb=0,se=n+1;
 13     for(int i=sb;i<=se;i++){
 14         head[i]=-1;
 15         in[i]=out[i]=0;
 16     }
 17 }
 18 void add(int u,int v,int w){
 19     S[sn].w=w;
 20     S[sn].v=v;
 21     S[sn].ne=head[u];
 22     head[u]=sn++;
 23 }
 24 void addE(int u,int v,int w){
 25     add(u,v,w);
 26     add(v,u,0);
 27 }
 28 bool bfs(){
 29     for(int i=sb;i<=se;i++) dep[i]=0;
 30     dep[sb]=1;
 31     int u,v,qn=0;
 32     q[++qn]=sb;
 33     while(qn>0){
 34         u=q[qn];
 35         qn--;
 36         for(int i=head[u];~i;i=S[i].ne){
 37             v=S[i].v;
 38             if(S[i].w>0&&!dep[v]){
 39                 dep[v]=dep[u]+1;
 40                 if(v==se) return true;
 41                 q[++qn]=v;
 42             }
 43         }
 44     }
 45     return false;
 46 }
 47 int dfs(int u,int minf){
 48     if(u==se||!minf) return minf;
 49     int v,flow;
 50     for(int &i=cur[u];~i;i=S[i].ne){
 51         v=S[i].v;
 52         if(S[i].w>0&&dep[v]==dep[u]+1){
 53             flow=dfs(v,min(minf,S[i].w));
 54             if(flow){
 55                 S[i].w-=flow;
 56                 S[i^1].w+=flow;
 57                 return flow;
 58             }
 59         }
 60     }
 61     return 0;
 62 }
 63 int dinic(){
 64     int maxf=0,flow;
 65     while(bfs()){
 66         for(int i=sb;i<=se;i++) cur[i]=head[i];
 67         while(flow=dfs(sb,inf)) maxf+=flow;
 68     }
 69     return maxf;
 70 }
 71 int main(){
 72     int t,u,v,d;
 73     scanf("%d",&t);
 74     while(t--){
 75         scanf("%d%d",&n,&m);
 76         init();
 77         for(int i=0;i<m;i++){
 78             scanf("%d%d%d",&u,&v,&d);
 79             in[v]++,out[u]++;
 80             if(!d) addE(u,v,1); 
 81         }
 82         int flag=1,sum1=0,sum2=0;
 83         for(int i=1;i<=n;i++){
 84             if(in[i]==out[i]) continue;
 85             if((in[i]-out[i])&1){
 86                 flag=0;
 87                 break;
 88             }
 89             else if(out[i]>in[i]){
 90                 sum1+=(out[i]-in[i])/2;
 91                 addE(sb,i,(out[i]-in[i])/2);
 92             }
 93             else{
 94                 sum2+=(in[i]-out[i])/2;
 95                 addE(i,se,(in[i]-out[i])/2);
 96             }
 97         }
 98         if(!flag||sum1!=sum2||dinic()!=sum1) printf("impossible\n");
 99         else printf("possible\n");
100     }
101     return 0;
102 }
poj
  1 #include<cstdio>
  2 #include<queue>
  3 #include<algorithm>
  4 using namespace std;
  5 const int N=118,M=1108,inf=1e9+7;
  6 struct Node{
  7     int v,ne,w;
  8 }S[M<<1],U[M<<1];
  9 char s[5];
 10 int sn,sb,se,head[N],cur[N],dep[N];
 11 int n,m,in[N],out[N],ok[N][N];
 12 int un,headu[N],cnt,ans[M<<1];
 13 void init(){
 14     sn=un=0;
 15     sb=0,se=n+1;
 16     for(int i=sb;i<=se;i++){
 17         head[i]=headu[i]=-1;
 18         in[i]=out[i]=0;
 19         for(int j=sb;j<=se;j++) ok[i][j]=0;
 20     }
 21 }
 22 void add(int u,int v,int w){
 23     S[sn].w=w;
 24     S[sn].v=v;
 25     S[sn].ne=head[u];
 26     head[u]=sn++;
 27 }
 28 void addE(int u,int v,int w){
 29     add(u,v,w);
 30     add(v,u,0);
 31 }
 32 void addu(int u,int v,int w){
 33     U[un].w=w;
 34     U[un].v=v;
 35     U[un].ne=headu[u];
 36     headu[u]=un++;
 37 }
 38 bool bfs(){
 39     for(int i=sb;i<=se;i++) dep[i]=0;
 40     dep[sb]=1;
 41     queue<int> q;
 42     q.push(sb); 
 43     int u,v;
 44     while(!q.empty()){
 45         u=q.front();
 46         q.pop();
 47         for(int i=head[u];~i;i=S[i].ne){
 48             v=S[i].v;
 49             if(S[i].w>0&&!dep[v]){
 50                 dep[v]=dep[u]+1;
 51                 if(v==se) return true;
 52                 q.push(v); 
 53             }
 54         }
 55     }
 56     return false;
 57 }
 58 int dfs(int u,int minf){
 59     if(u==se||!minf) return minf;
 60     int v,flow;
 61     for(int &i=cur[u];~i;i=S[i].ne){
 62         v=S[i].v;
 63         if(S[i].w>0&&dep[v]==dep[u]+1){
 64             flow=dfs(v,min(minf,S[i].w));
 65             if(flow){
 66                 S[i].w-=flow;
 67                 S[i^1].w+=flow;
 68                 return flow;
 69             }
 70         }
 71     }
 72     return 0;
 73 }
 74 int dinic(){
 75     int maxf=0,flow;
 76     while(bfs()){
 77         for(int i=sb;i<=se;i++) cur[i]=head[i];
 78         while(flow=dfs(sb,inf)) maxf+=flow;
 79     }
 80     return maxf;
 81 }
 82 void dfs2(int u){
 83     for(int &i=cur[u];i<=n;i++) 
 84     if(ok[u][i]){
 85         ok[u][i]--;
 86         dfs2(i);
 87     }
 88     ans[cnt++]=u;
 89 }
 90 int main(){
 91     int t,u,v,d;
 92     scanf("%d",&t);
 93     while(t--){
 94         scanf("%d%d",&n,&m);
 95         init();
 96         for(int i=0;i<m;i++){
 97             scanf("%d%d%s",&u,&v,s);
 98             in[v]++,out[u]++;
 99             if(s[0]=='U'){
100                 addu(u,v,sn);
101                 addE(u,v,1);
102             }
103             else ok[u][v]++;
104         }
105         int flag=1,sum1=0,sum2=0;
106         for(int i=1;i<=n;i++){
107             if(in[i]==out[i]) continue;
108             if((in[i]-out[i])&1){
109                 flag=0;
110                 break;
111             }
112             else if(out[i]>in[i]){
113                 sum1+=(out[i]-in[i])/2;
114                 addE(sb,i,(out[i]-in[i])/2);
115             }
116             else{
117                 sum2+=(in[i]-out[i])/2;
118                 addE(i,se,(in[i]-out[i])/2);
119             }
120         }
121         if(!flag||sum1!=sum2||dinic()!=sum1) printf("No euler circuit exist\n");
122         else{
123             for(int i=1;i<=n;i++){
124                 cur[i]=1;
125                 for(int j=headu[i];~j;j=U[j].ne){
126                     if(S[U[j].w].w>0) ok[i][U[j].v]++;
127                     else ok[U[j].v][i]++;
128                 }
129             }
130             cnt=0;
131             dfs2(1);
132             for(int i=cnt-1;i>=0;i--) printf("%d%c",ans[i]," \n"[i==0]);
133         }
134         printf("\n");
135     }
136     return 0;
137 }
uva

猜你喜欢

转载自www.cnblogs.com/LMCC1108/p/11306297.html
今日推荐