欧拉路,欧拉回路
1
经过图中所有边恰好一次的通路称为欧拉通路或欧拉路(通路一个点可以经过多次,如果是一个点只能通过一次为路径)
经过图中所有边恰好一次的回路称为欧拉回路,(回路是特殊的通路,起点和终点同一个点)
2 无向图欧拉路判断
欧拉回路的判别法:对于无向图G,G中存在欧拉回路当且仅当G中所有度非0的点是连通的且没有奇数度数的点
欧拉路的判断:对于无向图G,G中存在欧拉路当且仅当G中所有度非0的点是连通的,且奇数的点恰好有0个或者2个(0个即为欧拉回路)
3有向图欧拉路判断
欧拉回路的判别法:对于有向图G,G中存在欧拉回路当且仅当G中所有度非0的点是强连通的且每个点的入度和出度相同
欧拉路的判断:
{1将G中的有向边改成无向边后,G中所有非0的点是连通的,2最多只有一个出度减去入度为1,3最多只有一个点入度减出度为1 4其他所有点的入度等于出度}
4求欧拉路的流程 时间复杂度O(n+m)
先判断图中是否存在欧拉路(检查度非0的点的连通性以及度数)
采用dfs来构造求解欧拉路,以有向图为例子:
另P为最终的路径序列,记路径起点为x
dfs(node u):{
遍历u连出去的边u->v,且u->v之前是没有访问过的:
dfs(v)
将边u->v添加到路径序列P中
}
dfs(x)结束后,将P中记录的边倒序输出,求得欧拉路
5Code(有向图):
vector<int> edge[N+5];
int n,m,l,f[N+5],ind[N+5],outd[N+5],c[M+5];//f数组表示点x连出去的点已经遍历过几条了
inline void dfs(int x){
int len=edge[x].size();
for(;f[x]<len;){
int y=edge[x][f[x]];
f[x]++;
dfs(y);
c[++l]=y;
}
}
inline void Euler(){
int x=0,y=0,z=0;//x用来存起点的位置,y存入度比出度小一点的个数,z存入度和出度不同的点
for(int i=1;i<=n;i++){
if(ind[i]+1==outd[i])
x=i,++y;
if(ind[i]!=outd[i])
++z;
}
if(!(y==1&&z==2)||z){
cout<<"NO\n";
return;
}
//当不是所有点的入度和出度都相等时,只能存在(2最多只有一个出度减去入度为1,3最多只有一个点入度减出度为1)
for(int i=1;i<=n;i++)
if(ind[i])
x=i;//随便取一个入度不为0的点设置为起点
memset(f,0,sizeof(f));
l=0;
dfs(x);
c[++l]=x;
if(l==m+1)// 经过m条边,且每条边只经过一次,所有经过的点就有m+1个
{
cout<<"YES"<<'\n';
for(int i=l;i;--i)
cout<<c[i]<<' ';//逆序输出
}
else cout<<"NO\n";
}
6Code(无向图):
struct Node{
int y,idx;//y表示边走到哪,idx表示第几条边, 相同的边 边数相邻,可以直接通过异或1来获取 2^1=3,4^1=5等等
Node(int _y,int _idx){y=_y;idx=_idx};
};
vector<Node> edge[N+5];
int n,m,l,cnt=1,f[N+5],v[N+5],d[N+5],c[M+5];
bool b[2*M+2];
inline void dfs(int x){
for(;f[x]<v[x];){
int y=edge[x][f[x]].y,idx=edge[x][f[x]].idx;
if(!b[idx]){
f[x]++;
b[idx]=b[idx^1]=true;
dfs(y);
c[++l]=y;
}else
f[x]++;
}
}
inline void Euler(){
int x=0,y=0;//x表示起点,y表示度为奇数的点个数
for(int i=1;i<=n;i++)
if(d[i]&1)
x=i,++y;
if(y&&y!=2){
cout<<"NO\n";
return;
}
if(!x)
for(int i=1;i<=n;i++)
if(d[i])
x=i;
memset(f,0,sizeof(f));
memset(b,false,sizeof(b));
dfs(x);
c[++l]=x;
if(l!=m+1){
cout<<"NO\n";
return;
}
// 经过m条边,且每条边只经过一次,所有经过的点就有m+1个
cout<<"YES\n";
for(int i=l;i;--i)
cout<<c[i]<<' ';
}