简介
说到欧拉回路,相信大家都听说过柯尼斯堡七桥问题。
简单概括欧拉回路就是在一个双向图中,从一个节点开始经过图中的所有边,然后回到了起点,这个回路就是欧拉回路,这个从起点到起点的路径就是欧拉路径。同样如果从一个节点出发,经过图中所有的边,没有回到起点,就是欧拉通路。
定义
欧拉通路:设G=<V,E>是一个没有孤立点的无向图,则通过G中每条边一次且仅一次的通路称为欧拉通路。
欧拉回路:设G=<V,E>是一个没有孤立点的无向图,则通过G中每条边一次且仅一次的回路称为欧拉回路。
ps:
- 在欧拉通路或欧拉回路中边不能重复但顶点可以重复。
- 由于在欧拉通路或欧拉回路中包含了图的所有边且图中没有孤立点,所以一定包含了图的所有顶点.因此,存在欧拉通路或欧拉回路的图一定是连通图。
欧拉图:具有欧拉回路的图称为欧拉图。
欧拉回路存在情况: 1.节点的度数全都是偶数。 2.只有节点的度数为奇数,那么一定从奇数点开始。 3.存在两个奇数节点,那么一定从一个奇数点开始一个奇数点结束。(是欧拉通路)
欧拉通路的判断方法:
- 有向图:图连通,有一个顶点出度大于入度,有一个顶点入度大于出度,其余都是出度等于入度。
- 无向图:图连通,只有两个顶点是奇数度,其余都是偶数度。
欧拉回路的判断方法:
- 有向图:图连通,所有的顶点出度等于入度。
- 无向图:图连通,所有的顶点都是偶数度。
例题
七桥问题
哥尼斯堡七桥问题(以下简称七桥问题)。17世纪的东普鲁士有一座哥尼斯堡城(现在叫加里宁格勒,在波罗的海南岸),城中有一座岛,普雷格尔河的两条支流环绕其旁,并将整个城市分成北区、东区、南区和岛区4个区域,全城共有七座桥将4个城区连接起来。于是,产生了一个有趣的问题:一个人是否能在一次步行中经过全部的七座桥后再回到起点,且每座桥只经过一次。
我们可以把问题抽象:
将城区抽象为顶点,用A、B、C、D表示4个城区,将桥抽象为边,用7条边表示七座桥,抽象出七桥问题的数据模型如图(b)所示,从而将七桥问题抽象为一个数学问题:求经过图中每条边一次且仅一次的回路,后来人们称之为欧拉回路。欧拉回路的判定规则是:
- 如果通奇数个桥的城区多于两个,则不存在欧拉回路。
- 如果只有两个城区通奇数个桥,则可以从这两个城区之一出发找到欧拉回路。
- 如果没有一个城区通奇数个桥,则无论从哪里出发都能找到欧拉回路。
由上述判定规则得到求解七桥问题的基本思路:依次计算与每个顶点相关联的边的个数(称为顶点的度),根据度为奇数的顶点个数判定是否存在欧拉回路。
Hierholzer 算法
Hierholzer 算法是一种用于求欧拉路径的算法。
算法过程如下:
- 选择任一顶点为起点,遍历所有相邻边。
- 深度搜索,访问相邻顶点。将经过的边都删除。
- 如果当前顶点没有相邻边,则将顶点入栈。
- 栈中的顶点倒序输出,就是从起点出发的欧拉回路。
伪代码:
算法:EulerCircuit
输入:二维数组mat[n][n]
输出:度为奇数的顶点个数count。
1.count初始化为0;
2.下标i从0~n-1重复执行下述操作:
2.1 计算第i行元素之和degree;
2.2 如果degree为奇数,则count++;
3.返回count;
332. 重新安排行程
class Solution {
public:
unordered_map<string,priority_queue<string, vector<string>, std::greater<string>>> vec;
vector<string> answer;
void dfs(string target){
while(vec.count(target)&& vec[target].size() > 0){
string str = vec[target].top();
vec[target].pop();
dfs(str);
}
answer.push_back(target);
}
vector<string> findItinerary(vector<vector<string>>& tickets) {
for(auto ticket: tickets){
vec[ticket[0]].emplace(ticket[1]);
}
dfs("JFK");
reverse(answer.begin(),answer.end());
return answer;
}
};
753. 破解保险箱
class Solution {
public:
set<int> visted;
string answer;
int mod;
void dfs(int num,int N,int K){
int mod = pow(10,N - 1);
for(int i = 0;i < K;i++){
int node_val = num*10 + i;
if(!visted.count(node_val)){
visted.insert(node_val);
dfs(node_val % mod,N,K);
answer += (i + '0');
}
}
}
string crackSafe(int N, int K) {
dfs(0,N,K);
answer += string(N - 1, '0');
return answer;
}
};
参考
[1] 《数据结构与算法:C语言版》;胡明,王红梅