欧拉图路径求解:Hierholzer算法
CCF:201512-4送货
题解:
- 条件为奇数度的点有且仅有2个或者0个。并且连通,连通可以用并查集判断。
- 字典序最小就优先考虑数字小的点。
- 算法流程:
- dfs标记经过的边,且不再恢复,表示删除这一条边,然后经过下一个顶点dfs
- 当所有边都删除之后,把这个点加入到栈中,即dfs的时候是最后再放入点。
- 最后输出栈。
比如:
- 盗了一张图,我们看从1出发,1->2->3->4->2走不通了,如果遍历到这个点立刻放入就会出错,但是回溯就没问题。回溯就变成了2 4 3 2,回溯到1,1还有路可走继续5->6->1,走不通回溯1 6 5 1 。所以最后结果为2 4 3 2 1 6 5 1。倒着输出。
代码:(80分)
#include <bits/stdc++.h>
using namespace std;
int const N = 100000 + 10;
typedef pair<int,int>pii;
int degree[N],fa[N],vis[N];
int n,m,ans[N],cnt;
vector<pii>G[N];
int find(int x){
return fa[x] == x ? x : (fa[x] = find(fa[x]));
}
void Union(int x,int y){
int fx = find(x), fy = find(y);
if(fx != fy) fa[fx] = fy;
}
queue<int>q;
void dfs(int u){
for(int i=0;i<G[u].size();i++){
pii p = G[u][i];
if(!vis[p.second]){
vis[p.second] = true;
dfs(p.first);
}
}
ans[cnt++] = u;
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++) fa[i] = i;
for(int i=1;i<=m;i++){
int u,v;
cin>>u>>v;
G[u].push_back(pii(v,i));
G[v].push_back(pii(u,i));
++degree[u], ++degree[v];
Union(u,v);
}
int odd = 0, root = 0;
for(int i=1;i<=n;i++){
sort(G[i].begin(),G[i].end());
if(degree[i] & 1) odd++; //统计奇度数
if(find(i) == i) root++;
}
if(odd == 0 ||(odd == 2 && root == 1 && degree[1] % 2 == 1)){
dfs(1);
for(int i=cnt-1;i>=0;i--) printf("%d ",ans[i]); printf("\n");
}else{
printf("-1\n");
}
return 0;
}

浙公网安备 33010602011771号