欧拉图 学习笔记

定义

欧拉回路:通过图中每条边恰好一次的回路。

欧拉通路:通过图中每条边恰好一次的通路。

欧拉图:具有欧拉回路的图。

半欧拉图:具有欧拉通路但不具有欧拉回路的图。

欧拉图的判定

经过一个点,除了起点和终点必然有进有出。因此可以得到欧拉图的判定:

无向图是欧拉图或半欧拉图需要去掉孤立点后联通。欧拉图没有度数是奇数的点,半欧拉图有两个度数为奇数的点,分别是起点和终点。

有向图是欧拉图需要去掉孤立点后强联通,半欧拉图弱联通。欧拉图中点的入度均等于出度,而半欧拉图起点的出度比入度多一,终点入度比出度多一,其他点入度等于出度。

欧拉图的起点可以任选一个有度数的点。

先判完度数,可以保证每个连通块是半欧拉图。连通性只需要判断搜出来的路径有没有 \(m+1\) 个点。

Hierholzer 算法

一种找欧拉通路的算法。其实过程很简单,对图 DFS,经过一条边后直接删除这条边,在回溯时加入这条边,形成的就是倒着的欧拉通路。

感性理解,半欧拉图本身具有度数的性质,搜索时一定遵循一进一出,因此任意搜索都不会出现一个点的度数被用完。

具体实现时有一个优化:让链式前向星的 head 随着 \(i\) 一起变化,这样下次枚举不会重复遍历,类似当前弧优化,防止算法退化。复杂度 \(O(n+m)\)

模板UOJ117代码:

#include<bits/stdc++.h>
using namespace std;
int t,n,m;
struct edge{
  int v,nxt; 
}e[400005];
int head[100005],cnt=1,ans[400005];
void add(int u,int v){
  cnt++,e[cnt].v=v,e[cnt].nxt=head[u],head[u]=cnt;
}
void dfs1(int pos,edge e[],int head[],bool vis[],int ans[],int &cnt){
  for(int i=head[pos];i;i=head[pos]){
    head[pos]=e[i].nxt;
    if(!vis[i])vis[i]=vis[i^1]=1,dfs1(e[i].v,e,head,vis,ans,cnt),ans[++cnt]=(i&1?-i/2:i/2);
  }
}
bool hierholzer1(int n,int m,edge e[],int head[],int ans[]){
  int in[n+5],cnt=0;
  bool vis[m*2+5];
  memset(in,0,sizeof(in)),memset(vis,0,sizeof(vis));
  for(int i=1;i<=n;i++)for(int j=head[i];j;j=e[j].nxt)in[e[j].v]++,in[i]++;
  for(int i=1;i<=n;i++)if(in[i]/2&1)return 0;
  for(int i=1;i<=n;i++){
    if(in[i]){
      dfs1(i,e,head,vis,ans,cnt);
      break;
    }
  }
  if(cnt!=m)return 0;
  return 1;
}
void dfs2(int pos,edge e[],int head[],int ans[],int &cnt){
  for(int i=head[pos];i;i=head[pos])head[pos]=e[i].nxt,dfs2(e[i].v,e,head,ans,cnt),ans[++cnt]=i-1;
} 
bool hierholzer2(int n,int m,edge e[],int head[],int ans[]){
  int in[n+5],out[n+5],cnt=0;
  memset(in,0,sizeof(in)),memset(out,0,sizeof(out));
  for(int i=1;i<=n;i++)for(int j=head[i];j;j=e[j].nxt)in[e[j].v]++,out[i]++;
  for(int i=1;i<=n;i++)if(out[i]!=in[i])return 0;
  for(int i=1;i<=n;i++){
    if(out[i]){
      dfs2(i,e,head,ans,cnt);
      break;
    }
  }
  if(cnt!=m)return 0;
  return 1;
}
int main(){
  cin>>t>>n>>m;
  if(t==1){
    for(int i=1,u,v;i<=m;i++)cin>>u>>v,add(u,v),add(v,u);
    if(!hierholzer1(n,m,e,head,ans))return puts("NO"),0;
    puts("YES");
    for(int i=m;i>=1;i--)cout<<ans[i]<<' ';
  }
  else{
    for(int i=1,u,v;i<=m;i++)cin>>u>>v,add(u,v);
    if(!hierholzer2(n,m,e,head,ans))return puts("NO"),0;
    puts("YES");
    for(int i=m;i>=1;i--)cout<<ans[i]<<' '; 
  }
  return 0;
}

[[图论]]

posted @ 2024-03-01 09:38  lgh_2009  阅读(28)  评论(0)    收藏  举报