欧拉回路
此作品已弃稿,更详细讲解请看这
欧拉回路
如果图G中的一个路径包括每个边恰好一次,则该路径称为欧拉路径(Euler path)。
如果一个回路是欧拉路径,则称为欧拉回路(Euler circuit)。
具有欧拉回路的图称为欧拉图(简称E图)。具有欧拉路径但不具有欧拉回路的图称为半欧拉图。————百度百科
欧拉通路:
- 通过图中每条边且只通过一次,并且经过每一顶点的通路
欧拉回路:
- 通过图中每条边且只通过一次,并且经过每一顶点的回路
有向图的基图
- 忽略有向图所有边的方向,得到的无向图称为该有向图的基图
具有欧拉回路的无向图 G 被称为欧拉图
定理
- 无向图存在欧拉通路的充要条件是:图联通,并且只有两个奇度节点或者无奇度节点
- 无向图存在欧拉回路的充要条件:不存在奇度节点
- 有向图存在欧拉通路的充要条件是:基图联通,并且所有的顶点的出度和入度相等,或者除两个顶点外的出度和入度都相等,而这两个顶点中一个顶点的出度比入度大 1 ,一个顶点的出度比入度小 1
- 有向图存在欧拉回路的充要条件:基图联通,所有的顶点的出入度相同
欧拉路的构造
- 无向图为例
- 如果有奇度节点,那么起点就设成这个节点,否则就设成编号最小的节点
- 然后从起点开始搜索,然后按照一个逆序存到答案中
Code
#include<bits/stdc++.h>
using namespace std;
int edge[1000][1000];
//为了方便优先访问编号小的节点,这里使用邻接矩阵来存边
//如果使用vector来存图,那还需要对每个节点连接的边进行排序
int ans[1000000];
int degree[1000];//用于储存每个点的度,以求起点
int p=0;
void dfs(int now)
{
for(int i=1;i<=1000;i++)//顺序寻找可访问的边,优先找编号小的节点
{
if(edge[now][i])//若这条边尚未访问过
{
edge[now][i]--;//已访问过的边要删去,防止重复访问
edge[i][now]--;//有向图的话请删去这一行
dfs(i);
}
}
ans[++p]=now;//将访问的节点储存进答案数组
//由于递归的特性,这里储存的是逆序过程
}
int main()
{
ios::sync_with_stdio(false);
int n;
cin>>n;//边的个数
for(int i=1;i<=n;i++)
{
int a,b;
cin>>a>>b;
edge[a][b]++;
edge[b][a]++;//有向图的话删去这行
degree[a]++,degree[b]++;//两个点的度都+1
}
int start=0;
for(int i=1;i<=1000;i++)
{
if(degree[i]%2)//如果找到奇数点
{
start=i;//那这个奇数点就作为起点,由于顺序遍历,这个起点编号必定最小
break;
}
}
if(!start)//如果还没找到奇数点,说明是欧拉回路
{
for(int i=1;i<=1000;i++)
if(degree[i])//寻找最小的有度的点即可
{
start=i;
break;
}
}
dfs(start);//dfs寻找欧拉路
for(int i=p;i>=1;i--)
cout<<ans[i];//输出给定的欧拉路
}