首先我们来百度一下,欧拉路径以及回路的定义:
若图G中存在这样一条路径,使得它恰通过G中每条边一次,则称该路径为欧拉路径。若该路径是一个圈,则称为欧拉(Euler)回路。
具有欧拉回路的图称为欧拉图(简称E图)。具有欧拉路径但不具有欧拉回路的图称为半欧拉图。
通俗来说,就是欧拉路径就是图中的每条边经过却只经过一次的路径,而最后回到起点的路径就是欧拉回路。
那给你一个图怎么判断存不存在,欧拉路径或者欧拉回路呢
首先,判断图是不是连通的,这个就很简单了,dfs或者并查集都可以。
然后就是根据定理
欧拉路径的定理
连通的无向图有欧拉路径的充要条件是:
G中奇顶点(连接的边数量为奇数的顶点)的数目等于0或者2。
连通的无向图是欧拉环(存在欧拉回路)的充要条件是:
G中每个顶点的度都是偶数。
欧拉回路的定理
无向图存在欧拉回路的充要条件
一个无向图存在欧拉回路,当且仅当该图所有顶点度数都为偶数,且该图是连通图。
有向图存在欧拉回路的充要条件
一个有向图存在欧拉回路,所有顶点的入度等于出度且该图是连通图。
这四个定理很好理解,无向图的话,因为要把所有边走一遍且只走一边,那对于每个点来说,如果不是起点或者终点的话,那么度数应该是偶数,有一条进边就有一条对于的出边,然后是起点,出边应该多一条,终点应该入边多一条,所以度数是奇数。然后如果没有奇数点的话,那就是任意点都可以作为起点并且能走回它,那就是存在一个回路了,否则就是得两个奇数点,一个起点和一个终点。
有向图的话,就是分为入度出度,道理是一样的,然后我们就可以来做题了
欧拉回路
中文题,真模板题,给一个无向图,问存不在在欧拉回路,存在扣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 (弗罗莱) 算法通俗解释
网上也很多这个算法的代码以及解释,我就不多重复了,从代码量和运行时间来说,我觉得套圈法是更优的,然后直接来上题。
中文题,意思就是给定了连通并且保证能有解的无向图,要按字典序最小输出无向图的欧拉路径。
就先判断有没有奇度点,有的话以最小那个为起点,否则以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 }
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 }
中文题,无敌大整合,给你无向或者有向边,问有没有欧拉回路,没有就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 }
那如果是一个混合图的话,我们怎么办呢?
这涉及到最大流,不会最大流的可以去学一下。
具体步骤的话,直接引用Adela的混合图中欧拉回路,我就不重复了,直接说为什么。
想法其实就是,因为有向边的方向已经固定了,这没法更改,我们这样就是看能不能给无向边定一个方向,然后把整个图成为有向图,然后就是有向图的判定了。
而这个给定方向就是就是通过最大流的调整了,有向边就是统计入度出度,对于每条a与b之间无向边,我们先假定一个a->b的方向,然后统计出度入度,以及建一条流量为1从a到b的边,说明a到b之间有一条可以反向的无向边。
如果存在出度与入度奇偶性不同的点的话,肯定就不存在欧拉回路了,因为改变一条无向边的方向,对于两边的点来说,也就是出度-1,入度+1,或者出度+1,入度-1,奇偶性变化是一样的,如果一开始奇偶性就不同的话,肯定没法使得出度等于入度。
然后对于每个出度大于入度的点,我们把它与源点连一条流量为(出度-入度)/2的边,(出度-入度)/2其实就是需要改变多少条连到它上面的无向边,使得它出度等于入度。而对于入度大于出度的点,则是与汇点连一条流量为(入度-出度)/2的边。
所以最终能不能有欧拉回路,也就是看能不能满流,让每个点都满足出度等于入度的要求。
而欧拉路径的话,就是最多只能有两个出度与入度奇偶性不同的点,也就是终点和起点,然后我们找到这两个点,给它们连一条无向边,那处理就跟欧拉回路的一样了。
至于路径的输出,我们就看之前流量为1的那些边,如果流量变为0了,说明反向了,否则就是我们原定的方向,就用这些新的有向边和原来的有向边,然后有向图的欧拉回路就ok了。
直接挂三道题,题意就不说了,练一下英语吧~~~~~~~~
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 }
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 }
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 }