Poj 2230 Watchcow (欧拉回路)打印欧拉回路路径

点击打开题目链接

我之前在博客中写过如何判断一个图如何为欧拉回路,但是写的太过简略,在此再次说明一下欧拉回路是什么,顺写一下如何打印路径。

欧拉回路:欧拉回路就是从图上的一点出发,经过所有的边必须且只能一次,最终回到起点的路径。

如何判断一个图为欧拉回路:

1.对于任意一个图来说,必须这个图是连通的,不能有孤立的点。

2,在此分两种类型的图来说

 <1> 无向图:对于无向图来说度数为奇数的点的个数为0;

 <2>有向图:每个定点的入度等于出度。

判断连通我之前博客中有用DFS来判断,思路非常简单,用一个标记数组来标记点是否用过,然后dfs任意一点,然后把搜索到的标记,然后最后判断是否有点没有搜索到。

然后条件2只需要统计图中每个点的入度和出度即可判断。

以上是最基本的欧拉回路的条件。

欧拉回路有一种变形,就是不回到原点,,但是依旧要所有的边必须且只能一次,也就是所谓的一笔画问题。

对于这种问题,是否为一笔画的判断条件如下:

1.图必须连通,不存在孤立点。

2,在此分两种类型的图来说

 <1> 无向图:对于无向图来说度数为奇数的点的个数为2,一个为终点,一个为起点;

 <2>有向图:存在两个点,其入度不等于出度,其中一点出度比入度大1为路径的起点,另一个入度比出度大一为路径的终点。

以上是判断一个图是否为欧拉图。但是很多情况只知道如何判断是无法解决问题的,最重要的还是求出路径。

在此提供两种思路:

第一种特别简单,暴搜,按照边来搜索整张图,直到搜索出一跳路径包含所有边为止。但是时间复杂度太高=-=,慎用!!!

第二种是带有一定的技巧性,实际上就是标记边,考虑搜索的的过程,当我们搜索到一个回路时,无非是两种情况,是答案,或者不是答案。因为确定我们这个图是在欧拉回路上搜索的,那么一定存在,一个路径是答案。于此同时我们还要标记每一个我们找到的边。表示我们已经用过这条边。那么我们怎么简化这个过程呢,假设没有搜索到答案,我们搜索开始回溯时,找到了第一个可以向其他方向搜索的时候,我们一定可以,在这个方向上找到一条路径来形成一个到达原点的道路,这时候一定面临两种情况是答案或者不是答案。如果不是继续回溯,重复上述过程,知道搜索结束。

总结下来就是,每次搜索到某条边时,把这条边记录成已选择,并且回溯也不能将当前边的状态改变回来。,每次回溯时记录回溯的路径。

说了这么多来看一下这道题的题意:

一个人要在n个节点上走,最后必须走到。原点,并且每个两个节点之间必须走两次。让你找出这样的一条路径。

思路:欧拉回路解决

代码如下:

#include<iostream>
#include<cstring>
using namespace std;

const int N = 1e5 + 5;
const int M = 1e5 + 5;

struct EdgeNode{
	int to;
	int w;
	int next ;
};
EdgeNode Edges[M];
int head[N];
int n,m;

int ans[M];
int ansi = 0;
bool visit[2*M];
void DFS(int now){
	int k ;
	for(int k = head[now] ; k != -1 ; k = Edges[k].next){
		if(!visit[k]){
			visit[k] = true;
			//visit[k^1] = true;
			DFS(Edges[k].to);
			ans[ansi++] = Edges[k].to;
		}
	}
}
int main(){
	
	cin >> n >> m;
	memset(head,-1,sizeof(head));
	for(int i = 1; i <= 2*m ;i += 2){
		int a,b;
		cin >> a >> b;
		Edges[i].to = b;
		Edges[i].next = head[a];
		head[a] = i;
		Edges[i^1].to = a;
		Edges[i^1].next = head[b];
		head[b] = i ^ 1;
	}
//	for(int i = 1 ; i <= n ; i ++){
//		for(int k = head[i] ; k != -1 ; k = Edges[k].next)
//			cout << i << " " << Edges[k].to << endl;
//	}
	DFS(1);
	for(int i = 0 ;  i < ansi ; i++)
		cout << ans[i] << endl;
	cout << "1" << endl; 
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值