学习图论(三)——欧拉通路

欧拉通路(Euler)

一、概念
1.欧拉通路:通过图(有向图或者无向图)中的所有边,且每条边只通过一次的通路。
2.欧拉回路:当欧拉通路为回路时,称为欧拉回路。
3.欧拉图:具有欧拉通路的图。
4.半欧拉图:具有欧拉通路但没有欧拉回路的图。

二、判断方法

断欧拉路径是否存在的方法
1.有向图 : 图连通,当且仅当该图所有顶点数的度数为0(入度和出度相同),或者一个顶点的度数为1(入度=出度+1),另一个顶点的度数为-1(出度=入度+1),其他顶点的度数为0.
2.无向图:图连通,当且仅当该图所有顶点的度数为偶数,或者除了两个度数为奇数外其余的全是偶数。

断欧拉回路是否存在的方法
1.有向图:图连通,所有的顶点出度=入度。
2.无向图:图连通,所有顶点都是偶数度。

三、寻找欧拉通路——Fleury(弗罗莱)算法
算法思想(用自己的理解与话概括):寻找起点(通路中入度为奇数的点,或者回路中任意一个点),从起点开始找相邻的边,删掉相邻的边,当前点移动到已经删掉的边的另一个点,直到所有的边都删去 (基于DFS)。
原理(自我理解):先明白欧拉通路的定义,即图中每条边都通过且只通过一次。从起点开始,每次找到相邻的点就删去这两点之间的边。由于每条边只通过一次,所以如果是通路,那么删去这条边对往下的判断没有任何影响。所以每次访问一条边后都把它删掉,如果最后所有边都删除了,则说明有存在从起点到达终点的路径(欧拉通路),或者存在从起点开始最后又返回起点的路径(欧拉回路)。

四、代码
1、判断是否存在欧拉路径(无向图)——基于定义去实现代码

例题:HihoCoder1176(https://vjudge.net/problem/610192/origin)
AC代码

#include
#include
#include
using namespace std;
const int MAXN = 1e4+5;
struct Graph  //建立一个图
{
	vector v;
	int degree=0;
} g[MAXN];
int n,m,u,v;
int vis[MAXN];
//用DFS判断是否连通 
void DFS(int u)
{
	//标记每一个遍历到的点,因为DFS使所有边都被访问,如果最终存在点没有被访问,则说明该图不连通 
	vis[u]=1;
	for(int j=0; j>n>>m;
	for(int i=1; i<=m; ++i)
	{
		cin>>u>>v;
		//无向图,所有双向存边
		g[u].v.push_back(v);
		g[v].v.push_back(u);
		g[u].degree++;
		g[v].degree++;
	}
	int cnt=0;//计算有多少个度数为奇数的点
	for(int i=1; i<=n; ++i)
		if(g[i].degree%2)
			cnt++;
	DFS(1);
	string f("Full");
	for(int i=1; i<=n; ++i)
		//不存在欧拉通路的情况:不连通  或者  有超过两个入度为奇数的点 (定义) 
		if(!vis[i]||cnt>2)
			f="Part";
	cout<

2、输出欧拉路径(无向图)——基于定义实现代码
例题:HihoCoder1181(https://vjudge.net/problem/575354/origin)
算法思想上面已经说过了。
AC代码

/*
算法思想:寻找起点,从起点开始找相邻的边,删掉相邻的边,当前点移动到已经删掉的边的另一个点,直到所有的边都删去 
*/ 
#include
#include
using namespace std;
const int MAXN = 1e4;
int n,m,u,v;
vector path;//存储欧拉路径 
int edge[MAXN][MAXN];//存边 
int def[MAXN]; //入度 

void Fleury(int u)  //弗罗莱算法 
{
	for(int i=1; i<=n; ++i)//寻找与 U 相关的边 
		if(edge[u][i]>0)  //U 和 V 之间存在边 
		{
			edge[u][i]--;  //删边 
			edge[i][u]--;
			Fleury(i);
		}
	path.push_back(u);
}

int main()
{
	cin>>n>>m;
	for(int i=1,j=1; i<=m; ++i)
	{
		cin>>u>>v;
		edge[u][v]++;
		edge[v][u]++;
		def[u]++;
		def[v]++;
	}
	int sta=1;
	//寻找起点 :入度为奇数的边,若没有则说明有回路 
	for(int i=1; i<=n; ++i)
	{
		if(def[i]&1)
			sta=i;
	}
	Fleury(sta);
	//因为是无向图欧拉路径,所以不存在正序反序,按题目要求即可 
	for(int i=0; i

3.判断是否存在欧拉路径(有向图)
讲一下思路就好:同样是基于定义!!!
①是否连通,这种情况下无关有向无向,可以直接将图看成无向然后用Fleury算法去边,最后通过是否还存在相连的边来看图是否连通。或者跟上面一样用DFS判断所有点是否都有访问过。
②入度问题:依据定义很好解决。

四、紫书上的代码

void euler(int u)
{
	for(int v=0;v

个人理解:同样是判断是否所有边都有遍历。

你可能感兴趣的:(图论)