算法学习之欧拉回路

欧拉回路:

从无向图的一个节点出发走出一条道路,每条边恰好经过一次这样的,这样的道路称为“欧拉回路”(E图)

在欧拉道路中“进”,“出”是一一对应的(除了起点和终点之外),其他点的“进出”次数应该相等,即除了起点跟终点之外,其他点的度数应该是偶数;

如果一个图是无向连通图,且最多有两个奇点(度数为奇数),则一定存在欧拉回路,如果有两个奇点,必须从一个奇点出发到另一个奇点结束,如果不存在奇点,则可以从任意的点出发,必存在欧拉回路

对于有向图来说同样最多只能有两个点的出度不等于入度,而且必须把其中一个入度比出度大一的点作为起点,而入度比出度小一的点作为终点,当然忽略图的方向,图必须是连通的

例题理解(判断欧拉回路):

一笔画问题

时间限制: 3000 ms  |  内存限制: 65535 KB
难度: 4
描述

zyc从小就比较喜欢玩一些小游戏,其中就包括画一笔画,他想请你帮他写一个程序,判断一个图是否能够用一笔画下来。

规定,所有的边都只能画一次,不能重复画。

 

输入
第一行只有一个正整数N(N<=10)表示测试数据的组数。
每组测试数据的第一行有两个正整数P,Q(P<=1000,Q<=2000),分别表示这个画中有多少个顶点和多少条连线。(点的编号从1到P)
随后的Q行,每行有两个正整数A,B(0<A,B<P),表示编号为A和B的两点之间有连线。
输出
如果存在符合条件的连线,则输出"Yes",
如果不存在符合条件的连线,输出"No"。
样例输入
2
4 3
1 2
1 3
1 4
4 5
1 2
2 3
1 3
1 4
3 4
样例输出
No
Yes
来源
[张云聪]原创

//错误代码
//并没有判断图是否连通 

/*
#include<iostream>
#include<cstring>
#include<cstdlib>
#define MAX 1005
using namespace std;
int P,Q; 
int Map[MAX][MAX];
int Into[MAX],Outfrom[MAX];
int Euler(){
	int cont=0;
	for(int i=1;i<=P;i++){
		if(Into[i]%2){
			cont++;
		}
	}
	if(cont==2 || cont==0){
		return 1;
	}
	else return 0;
}
int main(){
	int N; cin>>N;
	while(N--){
		cin>>P>>Q;
		memset(Into,0,sizeof(Into));
		memset(Map,0,sizeof(Map));
		for(int i=0;i<Q;i++){
			int A,B; cin>>A>>B;
			Map[A][B]=Map[B][A]=1;
			Into[A]++,Into[B]++;
		}
		if(Euler()){
			cout<<"Yes"<<endl;
		}
		else cout<<"No"<<endl;
	}
} */
#include<iostream>
#include<cstring>
#include<queue>
#define MAX 1005
using namespace std;
int Map[MAX][MAX],visit[MAX];
int P,Q,con;//con用于记录连通点的个数 
int Euler(){
	int cont=0;//统计奇度点的个数 
	queue<int>q;
	q.push(1);
	visit[1]=1;
	while(!q.empty()){
		int t=q.front();
		q.pop();
		con++;
		int sum=0;//记录这个点的边数 
		for(int i=1;i<=P;i++){
			//sum=0;//记录这个点的边数 
			if(Map[t][i]){
				if(!visit[i]){
					visit[i]=1;
					q.push(i);
				}	
				sum++;
			}
		}
		if(sum%2){
			cont++;
		}
	} 
	return cont;
}
int main(){
	int T; cin>>T;
	while(T--){
		cin>>P>>Q;
		memset(visit,0,sizeof(visit));
		memset(Map,0,sizeof(Map));
		con=0;
		for(int i=0;i<Q;i++){
			int A,B; cin>>A>>B;
			Map[A][B]=Map[B][A]=1;
		}
		int cont=Euler();
		if((cont==0 || cont==2) && P==con){
			cout<<"Yes"<<endl;
		}
		else cout<<"No"<<endl;
	}
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值