前置知识:
欧拉图:能够遍历所有的边并最终回到起点的一种特殊的图;
半欧拉图:能够遍历所有的边但回不去最初的起点的一种特殊的图;
欧拉回路:从某一起点出发能够遍历所有边并最终回到起点的路径;
判断欧拉图:
无向图:度 == 偶数(进入一个结点后要离开,需要两条路径)
有向图:出度 == 入度(进入一个结点后要离开,进多少次就要离开多少次)
注意:判断欧拉图之前需要判断这个图是不是一个连通图!!!
Hierholzers算法:
没找到这个算法的名称,按照我的英语水平应该读作海尔霍兹算法
这个算法用于求解欧拉回路的路径,所以在运用之前需要确定这个图是不是欧拉图。
算法理解:
任何欧拉图都可以按照某一条路径展开为(抽象为)一个环:照着这条路径走下去,每走过一条边,到达另一个结点后就将原边删除(过河拆桥),这样子在最后来到某个结点时,会发现这个点已经没有边可以继续走下去了,(因为我们展开为一个环,同时也说明所有的边都已经删除完了),说明这个点即是起点也是终点,说明欧拉回路我们已经遍历完毕了,最后再层层递归回去就能将所有路径都记录下来。
然后附上算法代码加深印象:
void dfs(int x) {
for (int i = 1; i <= 50; i++) {
if (graph[x][i] > 0) {
graph[x][i]--;//graph表示是否连通
graph[i][x]--;
dfs(i);
bian e; e.from = x; e.to = i;
stk.push(e);//这里保存的路径是边的形式,所以定义了一个结构体
}
}
}
UVA-10054题目链接
AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
#define Mx 1008
using namespace std;
int graph[Mx][Mx];//有向图表示
int in[Mx];
int ot[Mx];
int ans[Mx];
struct bian {
int from, to;
};
stack<bian>stk;
void dfs(int x) {
for (int i = 1; i <= 50; i++) {
if (graph[x][i] > 0) {
graph[x][i]--;
graph[i][x]--;
dfs(i);
bian e; e.from = x; e.to = i;
stk.push(e);
}
}
}
bool judge() {
for (int i = 1; i <= 50; i++) {
if (ot[i] != in[i])
return false;
if (ot[i] & 1)
return false;
}
return true;
}
int main() {
int t;
while (cin >> t) {
for (int ww = 1; ww <= t; ww++) {
memset(graph, 0, sizeof(graph));
memset(in, 0, sizeof(in));
memset(ot, 0, sizeof(ot));
stack<bian>emp;
stk = emp;
int n; cin >> n;
int mmin = 0, fuck = n;
while (n--) {
int a, b;
cin >> a >> b;
if (fuck == n + 1)
mmin = a;
graph[a][b]++;
graph[b][a]++;
in[a]++; ot[a]++;
in[b]++; ot[b]++;
}
printf("Case #%d\n", ww);
if (!judge()) {
printf("some beads may be lost\n\n");
continue;
}
dfs(mmin);
while (!stk.empty()) {
bian ff = stk.top(); stk.pop();
cout << ff.from << " " << ff.to << endl;
}
printf("\n");
}
}
return 0;
}