欧拉道路:即一笔画,从图的一个结点出发走出一条道路,每条边恰好经过一次
欧拉回路:从任意点出发,最终回到该点的欧拉道路
1.前提:忽略边的方向后,图是连通的【dfs、bfs、并查集】
2.条件:
有向图:最多只有两个点的入度不等于出度,且相差的绝对值是1
无向图:最多只有两个点的度是奇数
3.若有特殊点,则特殊的点为起点,若无任意点都可为起点
寻找路径方法:DFS构造
一般的版本
void euler(int u) {
for (int v = 0; v < n; ++v)
if (G[u][v] && !vis[u][v]) {
vis[u][v] = vis[v][u] = 1;
euler(v);
path.push_back(v);
}
}
递归版本(图很大,不能用邻接矩阵)
#include<iostream>
#include<vector>
using namespace std;
const int maxn = 10005;
const int maxm = 100005;
struct Edge{
int M,vis;//M是u+v
Edge(int a = 0,int c = 0) : M(a), vis(c) {};
};
vector<Edge> Edges;
vector<int> G[maxn];//G[k]代表k结点相连的路径编号(Edges[]编号)
vector<int> path;
int n, m,a,b;
void euler(int u) {
for (int i=0;i<G[u].size();++i)
if (!Edges[G[u][i]].vis) {
int v = Edges[G[u][i]].M - u;
Edges[G[u][i]].vis = 1;
euler(v);
path.push_back(v);
}
}
迭代版本(栈溢出的情况下使用)
#include<iostream>
#include<vector>
using namespace std;
const int maxn = 10005;
const int maxm = 100005;
struct Edge{
int M,vis;
Edge(int a = 0,int c = 0) : M(a), vis(c) {};
};
vector<Edge> Edges;
vector<int> G[maxn];//G[k]代表k结点相连的路径编号(Edges[]编号)
vector<int> path;
int n, m,a,b,i;
Edge x;
vector<Edge> sta;//代表:M=u,vis=i
void euler(int u) {
i = 0;
while (1) {
for (; i<G[u].size(); ++i)
if (!Edges[G[u][i]].vis) {
int v = Edges[G[u][i]].M - u;
Edges[G[u][i]].vis = 1;
sta.push_back(Edge(u, i));
u = v; i = 0;
break;
}
if (!i) continue;//只有break下来的i是等于0的,其他都是>0,不存在不连通图的欧拉路径
if (sta.empty()) break;
x = sta.back(); sta.pop_back();
u = x.M, i = x.vis;
path.push_back(Edges[G[u][i++]].M - u);
}
}