图论:欧拉图
欧拉道路描述的是无向图的一个顶点出发的一条道路能够经过每条边恰好一次
欧拉回路指的是任意点出发都满足上述性质
如果一个图是欧拉道路或者欧拉回路,必须满足两个条件
第一个条件,这个图是连通图
第二个条件,所有点的度数满足“一定的关系”
然后我们阐述一下“一定的关系”是什么
检查这个图所有点的度数,求出这个图度数给奇数的点的个数,我们也可以称之为奇点数
如果没有奇点,这个图是一个欧拉回路,从任意点出发可以经过所有的边并回到这个点
如果存在两个奇点(这两个奇点具有这样的性质,这两个点分别为起点和终点,其中起点的出度比入度大1,终点的入度比出度大1),那么这个图是一个欧拉道路
然后我们看一下程序怎么写,这里只给出了求欧拉回路的程序
思路是这样的,先判连通,然后计算点的度数,如果有奇点就肯定不是欧拉回路了(有可能是欧拉道路)
- int n,m;
- int G[maxn][maxn],a[maxn],vis[maxn],vi[maxn][maxn];
n个点m条边
G邻接矩阵,a是统计每一个点度数的,vis是判连通时用到的数组,而vi是打印欧拉路径的时候的判重数组
- void dfs(int u)
- {
- for(int i=1;i<=n;i++)
- if(G[u][i]&&!vis[i]){vis[i]=1;dfs(i);}
- }
判连通,超热血的DFS
- void euler(int u) //如果不是欧拉回路,参数必须传道路起点
- {
- for(int v=1;v<=n;v++)
- if(G[u][v]&&!vi[u][v]){vi[u][v]=vi[v][u]=1;euler(v);printf("%d %d\n",u,v);}
- //有向图中去掉vi[v][u],真正路径把printf压栈
- }
打印欧拉路径的函数,也十分热血
下面给出完整实现,这个程序是判断欧拉回路的一定要注意
- 1 #include<iostream>
- 2 #include<cstring>
- 3 using namespace std;
- 4 const int maxn=1005;
- 5 int n,m;
- 6 int G[maxn][maxn],a[maxn],vis[maxn],vi[maxn][maxn];
- 7 void dfs(int u)
- 8 {
- 9 for(int i=1;i<=n;i++)
- 10 if(G[u][i]&&!vis[i]){vis[i]=1;dfs(i);}
- 11 }
- 12 void euler(int u) //如果不是欧拉回路,参数必须传道路起点
- 13 {
- 14 for(int v=1;v<=n;v++)
- 15 if(G[u][v]&&!vi[u][v]){vi[u][v]=vi[v][u]=1;euler(v);printf("%d %d\n",u,v);}
- 16 //有向图中去掉vi[v][u],真正路径把printf压栈
- 17 }
- 18 int main()
- 19 {
- 20 while(cin>>n)
- 21 {
- 22 memset(G,0,sizeof(G));
- 23 memset(a,0,sizeof(a));
- 24 memset(vis,0,sizeof(vis));
- 25 if(n==0) break;
- 26 cin>>m;
- 27 for(int i=1;i<=m;i++){int x,y;cin>>x>>y;G[x][y]=1;G[y][x]=1;}
- 28 bool flag=1;int tmp=0;
- 29 vis[1]=1;dfs(1);
- 30 for(int i=1;i<=n;i++)
- 31 if(vis[i]==0) flag=0;
- 32 if(flag)
- 33 {
- 34 for(int i=1;i<=n;i++)
- 35 for(int j=1;j<=n;j++)
- 36 if(G[i][j]) a[i]++;
- 37 for(int i=1;i<=n;i++)
- 38 if(a[i]%2!=0) tmp++;
- 39 }
- 40 if(flag&&tmp==0) cout<<1<<endl;
- 41 else cout<<0<<endl;
- 42 }
- 43 return 0;
- 44 }
如果一个问题可以转换成求欧拉道路或者欧拉回路的形式,那答案就显然了