欧拉回路:
从无向图的一个节点出发走出一条道路,每条边恰好经过一次这样的,这样的道路称为“欧拉回路”(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
来源
- [张云聪]原创
-
第一行只有一个正整数N(N<=10)表示测试数据的组数。
//错误代码
//并没有判断图是否连通
/*
#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;
}
}