欧拉回路学习笔记

1.定义

通俗的讲,欧拉回路是从图上某一点出发,经过一系列不重复的边,然后再回到开始节点的路径。
注意,这个过程可以经过重复的节点 比如图中仅有一个点,有 (998244353) 个自环,但这些自环仍然可以构成欧拉回路。

2.存在条件

  • 有向图
    每个节点入度等于出度
  • 无向图
    每个节点度均为偶数

3.求解方法

比较简单,从一个点出发进行dfs,在回溯的时候把当前边加入答案队列。
但有以下情况需要考虑

  • 图不连通
    无解。前提是至少两个连通块内有边
  • 单独一个点
    可以忽略,不对答案产生影响。因为欧拉回路关心的是经过所有边 单独一个点不会影响答案
  • 优化
    如果不加当前弧优化,复杂度是 (O(nm))
    加上后能优化到 (O(n+m))

4.例题&代码

模板-UOJ117
分别对有向图和无向图找出欧拉回路,输出路径。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<map>
#include<cstring>
#include<stack>
#include<queue>
#include<vector>
#include<bitset>
#define ll long long
using namespace std;
const int inf = 0x7fffffff;
int T,n,m;
#define maxn 400009
int in[maxn],ans[maxn],out[maxn];
int nxt[maxn],head[maxn],to[maxn];
bool ban[maxn],vis[maxn];
namespace fuckccf//无向边 
{
	int num=0,cnt=1;//!!!从1开始记录 
	void Add(int x,int y){cnt++;nxt[cnt]=head[x];to[cnt]=y;head[x]=cnt;}//邻接表 
	void dfs(int x)
	{
		ban[x]=1;
		for(int &i=head[x];i;i=nxt[i])//当前弧 
		{
			int t=to[i],j=i>>1,val=i;//!!!进行完dfs之后i的值会改变 要提前存下来 
			if(vis[j])continue;
			vis[j]=1;
			dfs(t);
			num++;
			if(val&1)ans[num]=-j;//如果是正向的 i末尾是0 否则是1 
			else ans[num]=j;
		}
	}
	void main()
	{
		scanf("%d%d",&n,&m);
		for(int i=1;i<=m;i++)
		{
			int x,y;
			scanf("%d%d",&x,&y);
			Add(x,y);
			Add(y,x);
			in[x]++;
			in[y]++;
		}
		for(int i=1;i<=n;i++)if(in[i]&1){printf("NO
");return;}//判断无解 
		for(int i=1;i<=n;i++)
		{
			if(!ban[i])dfs(i);
			if(num&&num<m)//走了一些边,但没走完,说明图不连通或者无解 
			{
				printf("NO
");
				return;
			}
		}
		printf("YES
");
		
		for(int i=m;i>=1;i--)
		{
			printf("%d ",ans[i]);
		}
	}
}
namespace tymXINzhy//有向边 
{
	int num=0,cnt=0;
	void Add(int x,int y){cnt++;nxt[cnt]=head[x];to[cnt]=y;head[x]=cnt;}
	void dfs(int x)
	{
		ban[x]=1;
		for(int &i=head[x];i;i=nxt[i])
		{
			int t=to[i],val=i;
			if(vis[i])continue;
			vis[i]=1;
			dfs(t);
			num++;
			ans[num]=val;//直接记录边即可 
		}
	}
	void main()
	{
		scanf("%d%d",&n,&m);
		for(int i=1;i<=m;i++)
		{
			int x,y;
			scanf("%d%d",&x,&y);
			Add(x,y);
			in[y]++;
			out[x]++;
		}
		
		for(int i=1;i<=n;i++)if(in[i]!=out[i]){printf("NO
");return;}
		for(int i=1;i<=n;i++)
		{
			if(!ban[i])dfs(i);
			if(num&&num<m)
			{
				printf("NO
");
				return;
			}
		}
		printf("YES
");
		for(int i=m;i>=1;i--)
		{
			printf("%d ",ans[i]);
		}
	}
}
signed main()
{
//	freopen("h.in","r",stdin);
	scanf("%d",&T);
	if(T==1)fuckccf::main();
	else tymXINzhy::main();
	return 0;
}
`
原文地址:https://www.cnblogs.com/lzy-blog/p/15426261.html