欧拉图路径求解:Hierholzer算法

CCF:201512-4送货

题解:

  • 条件为奇数度的点有且仅有2个或者0个。并且连通,连通可以用并查集判断。
  • 字典序最小就优先考虑数字小的点。
  • 算法流程:
  1. dfs标记经过的边,且不再恢复,表示删除这一条边,然后经过下一个顶点dfs
  2. 当所有边都删除之后,把这个点加入到栈中,即dfs的时候是最后再放入点。
  3. 最后输出栈。

比如:

  • è¿éåå¾çæè¿°
  • 盗了一张图,我们看从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;
}

 

posted @ 2019-03-11 17:07  月光下の魔术师  阅读(50)  评论(0)    收藏  举报