欧拉路径问题

先普及一下概念:

 如果图G中的一个路径包括每个边恰好一次,则该路径称为欧拉路径(Euler path)。
 如果一个回路是欧拉路径,则称为欧拉回路(Euler circuit)。
 具有欧拉回路的图称为欧拉图(简称E图)。具有欧拉路径但不具有欧拉回路的图称为半欧拉图。

判断一个图是否存在欧拉回路:

无向图:图中度数为奇数的点的数量为0,也就是一笔画问题中起点和终点可以随便选一个且为同一个的那种。
有向图:图中所有点的入度等于出度。

判断一个图是否存在欧拉路径:

无向图:图中度数为奇数的点的数量为0或2,也就是经典的一笔画问题。
有向图:图中除了起点和终点所有点的入度等于出度,起点的入度比出度小1,终点的入度比出度大1。

代码如何判断是否存在?

很简单,在读入边的时候O(m)记录入度和出度,之后O(n)扫一遍就好了,这边不举出代码了。

如何找到一条欧拉路径?

这里介绍一个方法,好像叫Hierholzer 算法
从起点开始dfs,然后不走重复的边,发先走不了的时候回溯,在回溯的时候把这时访问的节点放到一个栈里,然后等dfs结束后应该栈里有m个节点(通常m>n因此有些点被重复记录,这也正是我们想要的)
然后你会惊奇的发现,将这m个节点的出栈顺序便是一条可行的欧拉路径!



代码(以无向图为例,有向图不建反向边即可)
#include<cstdio>
#include<cstring>
const int N=110000,M=220000;
struct node{
	int x,y,next;
}data[M];//邻接表 
int n,m,num,s;
int h[N];//邻接表 
bool flag[M];//访问边标记 
int d[N];//degree度数 
int b[M],top;//不知道起什么名字好 
void ins(int x,int y)
{
	data[++num].x=x;
	data[num].y=y;
	data[num].next=h[x];
	h[x]=num;
}
void dfs(int u)
{
	for(int i=h[u];i!=-1;i=data[i].next)
	{
		if(flag[i]) continue;
		int v=data[i].y;
		flag[i]=true;
		flag[i^1]=true;//反向边也打上标记 
		dfs(v);
		b[++top]=v;
	}
}
int main()
{
	scanf("%d%d",&n,&m);
	num=-1;//这样使用^可以直接得到反向边 
	memset(h,0xff,sizeof h);//全赋-1 
	for(int i=1;i<=m;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		ins(x,y);d[x]++;
		ins(y,x);d[y]++;
	}
	int num1=0;
	for(int i=1;i<=n;i++)
		if(d[i]&1)
		{
			num1++;
			if(!s) s=i;
		}
	if(num1!=0 && num1!=2)
	{
		printf("NO\n");//不存在欧拉路径 
		return 0;
	}
	printf("YES\n");//存在欧拉路径/回路 
	if(!s) s=1;//存在欧拉回路 
	dfs(s);
	b[++top]=s;//起点入栈 
	while(top) printf("%d ",b[top--]);//出栈 
	return 0;
}
应该没写错吧,如果写错了请告诉我谢谢
好像这是我第一次发表博客的样子



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值