欧拉路径就是一笔画问题,在一个连通图中,一笔走完所有路径不能有重复路径。
无向图:
具有欧拉回路的 充要条件 图连通,所有点的度数为偶数
具有欧拉路径的 充要条件 图连通,具有0个或者2个奇数度数的结点
有向图:
具有欧拉回路的 充要条件 图连通,所有点的入度等于出度
具有欧拉路径的 充要条件 图连通,一个点的出度大入度1度,一个点的入度大于出度1度,其余点出度等于入度。
Fleury算法跟Hierhoizer算法很相似,但是Hierhoizer算法更快一点,遍历一遍图就可以了。
我感觉核心思想就是圈套圈,有欧拉回路的图可以抽象为很多圈套在一起,试想一下给你很多圈相切的图形,你该如何一笔画?当然是遇到切点就进入切点的园中继续走遇到切点就走。
Hierhoizer算法的思想就是如此。寻找欧拉回路的时候正确的起点出发,遍历该节下一个结点,然后删除此边重复此步骤,在一个存在欧拉路径的路中会找到一个环,然后用一个stack存储路径,从递归深处存储,遇到还有为访问完路径的结点就继续访问,这等价于全是园的图中遇到切点,我们就进入切点继续访问。
看代码辅助理解一下:
vector<int> G[10000]; //邻接表存图
int nums[1000][1000]; //存边的条数
stack<int> path;
void dfs(int s) { //起点
for(auto v:G[s]) { //遍历该结点的所有路径
if(nums[s][v] >= 1) { //有路
nums[s][v]--; //删除路
dfs(v); //遍历下一个结点
}
}
path.push(s); //此结点没有路径可走加入路径中
}
最后输出path就可以了,stack存的是反路径,从顶取出就是正确路径了。
我们用dfs的特点来模仿遇到切点就进入,因为dfs只有平行状态执行完毕才算这层递归执行完毕。
Fleury算法思想很类似,不过它这个算法是这么说的:
访问一条边就删除这条边。
优先访问不是桥的边。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<vector>
using namespace std;
const int N = 1005;
int n, m, flag, top, sum, du[N], ans[5005], map[N][N];
void dfs(int x)
{
ans[++top] = x;
for(int i = 1; i <= n; i++)
{
if(map[x][i] >= 1)
{
map[x][i]--;
map[i][x]--;
dfs(i);
break;
}
}
}
void fleury(int x)
{
top = 1;
ans[top] = x;
while(top > 0)
{
int k = 0;
for(int i = 1; i <= n; i++)//判断是否可扩展
{
if(map[ans[top]][i] >= 1)//若存在一条从ans[top]出发的边 那么就是可扩展
{k = 1; break;}
}
if(k == 0)//该点x没有其他的边可以先走了(即不可扩展), 那么就输出它
{
printf("%d ", ans[top]);
top--;
}
else if(k == 1)//如可扩展, 则dfs可扩展的哪条路线
{
top--;//这需要注意
dfs(ans[top+1]);
}
}
}
int main()
{
while(scanf("%d%d", &n, &m) != EOF)
{
memset(du, 0, sizeof(du));
memset(map, 0, sizeof(map));
for(int i = 1; i <= m; i++)
{
int x, y;
scanf("%d%d", &x, &y);
map[x][y]++; //记录边, 因为是无向图所以加两条边, 两个点之间可能有多条边
map[y][x]++;
du[x]++;
du[y]++;
}
flag = 1; // flag标记开始点。 如果所有点度数全为偶数那就从1开始搜
sum = 0;
for(int i = 1; i <= n; i++)
{
if(du[i] % 2 == 1)
{
sum++;
flag = i;// 若有奇数边, 从奇数边开始搜
}
}
if(sum == 0 || sum == 2)
fleury(flag);
}
return 0;
}
这个算法类似与把Hierhoizer给细分了,一个dfs专门找回路,然后把访问完周围结点的点加入答案,遇到还可以访问其他结点的点就继续dfs,也就是我所说的进入切点。他给拆开了,更好理解,也可看出时间复杂度高于Hierhoizer算法每个出栈的点都要判断一下是不是可以扩展路径。我并没从此代码看出不选桥的特点,可能是我看不出来吧。
来源:CSDN
作者:桐乐AC
链接:https://blog.csdn.net/qq_43645188/article/details/104598838