欧拉回路与欧拉道路

来源:互联网 发布:大数据属于工业么 编辑:程序博客网 时间:2024/04/29 15:04

      

图G的一个回路,若它恰通过G中每条边一次,则称该回路为欧拉(Euler)回路。
如果一个图只是形成一个连通所有节点的链,且每一点只走一次,则成为欧拉道路。
具有欧拉回路或欧拉道路的图称为欧拉图(简称E图)。
有向图的欧拉回路
一个有向图存在欧拉回路的前提条件是这个图是个连通图,其次要求其每个点的入度等于出度,或者其中有一个点的出度比入度大1,另一个点的入度比出度大一这样就存在一条欧拉回路。
如果其每个点的入度等于出度则从任意一点出发,可以走出一条欧拉回路,如果是第二种情况,则必须从出度大于入度 1 的点出发到入度大于出度 1 的点结束,走出一条欧拉道路。
无向图的欧拉回路
跟有向图一样,首先必须连通,其次如果最多只有两个奇点。则满足欧拉回路或欧拉道路,有奇点就从任意一个奇点出发找科形成一条欧拉道路,否则从任意一点出发都能找出欧拉回路。(注意:百度百科上是错的)

如果只是判断一个图是否能够形成欧拉回路的话,就用上面的思路:
首先根据出度跟入度的关系,判断是否满足要求
然后用判断图的连通性可以用并查集或者Dfs如果要求路径的话可以用Dfs

要是需要求出欧拉路径,就用下面这个函数。
下面这个程序,是通过遍历一个图来求其欧拉回路或欧拉道路的。如果需要打印欧拉道路,在主程序中调用,参数必须是道路的起点,另外说明的是,这样打印出来是逆序的,因此在使用的时候,应该用栈压入栈中,还有就是其对无向图和有向图遍历都有用。其实这个算法跟最小生成树prim里面每次求连接上一边最小权值的边算法一样,这个只是那个算法的一个简化。可根据那个进行理解。
[cpp] view plaincopyprint?
  1. void euler(int u)  
  2. {  
  3.     for(int v=0;v<n;v++)  
  4.     {  
  5.         if(map[u][v] && !vis[u][v])  
  6.         {  
  7.             vis[u][v] = vis[v][u] = 1;//如果是有向图的只需判断一个  
  8.             euler(v);  
  9.             printf("%d %d\n",u,v);  
  10.         }  
  11.     }  
  12. }  

uva10054 - The Necklace

这个题题意很容易理解,一个链子断了,链子上的珠子两边分别有两个值,要把所有珠子链起来的话任意两个相邻的珠子的值必须相等才行,另外要说的是第二组数据是一组很好的数据。可根据其推出是用无向图,首先判断是否满足每个点都是偶点(因为是回路,不是道路)。然后利用上面欧拉代码遍历输出即可。

[cpp] view plaincopyprint?
  1. #include <cstdio>  
  2. #include <cstring>  
  3. #include <stack>  
  4. #define Max 60  
  5. using namespace std;  
  6. int map[Max][Max];  
  7. int in[Max];  
  8. struct E{ int u, v; } tmp;  
  9. stack <E> st;  
  10.   
  11. void euler( int u )  
  12. {  
  13.     for ( int v = 1; v < n; ++v ) if ( map[u][v] )  
  14.     {  
  15.         map[u][v]--; map[v][u] = map[u][v];  
  16.         euler( v );  
  17.         tmp.u = u, tmp.v = v;  
  18.         st.push(tmp);  
  19.     }  
  20. }  
  21. int main()  
  22. {  
  23.     int n,T,a,b;  
  24.     scanf("%d",&T);  
  25.     for(int cas=1;cas<=T;cas++)  
  26.     {  
  27.         scanf("%d",&n);  
  28.         memset(map,0,sizeof(map));  
  29.         memset(in,0,sizeof(in));  
  30.         //memset(out,0,sizeof(out));  
  31.         for(int i=0;i<n;i++)  
  32.         {  
  33.             scanf("%d%d",&a,&b);  
  34.             ++in[a];++in[b];  
  35.             ++map[a][b];  
  36.             map[b][a]=map[a][b];  
  37.         }  
  38.         bool ok=true;  
  39.         for(int i=0;i<=50;i++)  
  40.         {  
  41.             if(in[i]%2)  
  42.                 ok=false;  
  43.         }  
  44.         printf("Case #%d\n",cas);  
  45.         if(!ok)  
  46.         printf("some beads may be lost\n");  
  47.         else  
  48.         {  
  49.             euler(a);  
  50.             while ( !st.empty() ) {  
  51.                 tmp = st.top(); st.pop();  
  52.                 printf("%d %d\n", tmp.u, tmp.v);  
  53.             }  
  54.         }  
  55.         printf("\n");  
  56.     }  
  57.     return 0;  
  58. }  


UVA10129 - Play on Words 这道题题意是给出n个单词,让每个点此的首字母指向未字母形成连通,这样形成一个有向图,求这个有向图的欧拉回路。

思想就是:首先读入图,然后根据出度和入度判断是否满足,单手Dfs判断连通性。
[cpp] view plaincopyprint?
  1. #include<stdio.h>  
  2. #include<string.h>  
  3. #include<math.h>  
  4. int visit[26],a[26][26];  
  5. void dfs(int x)  
  6. {  
  7.     int i;  
  8.     visit[x]=0;  
  9.     for (i=0;i<26;i++)  
  10.     if ((visit[i]==1)&&(a[x][i]==1)) dfs(i);  
  11. }  
  12. int main()  
  13. {  
  14.     int f,t,k1,k2,num,n,i,j,l,in[26],out[26];  
  15.     char s[1010];  
  16.     scanf("%d",&t);  
  17.     while (t--)  
  18.     {  
  19.         memset(a,0,sizeof(a));  
  20.         for (i=0;i<26;i++)  
  21.         {in[i]=0; out[i]=0; visit[i]=0;}  
  22.         scanf("%d\n",&n);  
  23.         while (n--)  
  24.         {  
  25.             gets(s); l=strlen(s);  
  26.             k1=s[0]-'a'; k2=s[l-1]-'a';  
  27.             ++in[k1]; ++out[k2];  
  28.             visit[k1]=1; visit[k2]=1;  
  29.             a[k1][k2]=1;  
  30.             num=k1;  
  31.         }  
  32.         for (i=0;i<26;i++)  
  33.         in[i]=in[i]-out[i];  
  34.         f=0; k1=0; k2=0;  
  35.         for (i=0;i<26;i++)  
  36.         {  
  37.             if (in[i]==-1) ++k1;  
  38.             else if (in[i]==1)  {++k2;num=i;} //因为是有向图,如果不是欧拉回路的情况,随便找个点为起点dfs不一定能遍历所有点,如3 a b b c c d只能以a为起点否则就会判断连通性错误  
  39.             else if (in[i]!=0)  f=1;  
  40.         }  
  41.   
  42.         if (f==0)  
  43.         {  
  44.             if ((k1+k2==0) || ((k1==1)&&(k2==1)))  
  45.             {  
  46.                 dfs(num);  
  47.                 for (i=0;i<26;i++)  
  48.                 f+=visit[i];  
  49.             }  
  50.             else f=1;  
  51.         }  
  52.         if (f!=0) printf("The door cannot be opened.\n");  
  53.        else printf("Ordering is possible.\n");  
  54.   
  55.     }  
  56.     return 0;  
  57. }  
  58.  
0 0
原创粉丝点击