欧拉回路
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 18525 Accepted Submission(s): 7193
Problem Description
欧拉回路是指不令笔离开纸面,可画过图中每条边仅一次,且可以回到起点的一条回路。现给定一个图,问是否存在欧拉回路?
Input
测试输入包含若干测试用例。每个测试用例的第1行给出两个正整数,分别是节点数N ( 1 < N < 1000 )和边数M;随后的M行对应M条边,每行给出一对正整数,分别是该条边直接连通的两个节点的编号(节点从1到N编号)。当N为0时输入结
束。
Output
每个测试用例的输出占一行,若欧拉回路存在则输出1,否则输出0。
Sample Input
3 3
1 2
1 3
2 3
3 2
1 2
2 3
0
Sample Output
1
0
Source
Recommend
We have carefully selected several similar problems for you: 1879 1880 1877 1881 1863
若图G中存在这样一条路径,使得它恰通过G中每条边一次,则称该路径为欧拉路径。
若该路径是一个圈,则称为欧拉(Euler)回路。具有欧拉回路的图为欧拉图。
定理:
(一)一个图有欧拉回路当且仅当它是连通的且每个顶点都有偶数度。
(二)一个图有欧拉通路当且经当它是连通的且除两个顶点外,其他顶点都有偶数度。
在第二个定理下,含奇数度的两个节点中,一个必为欧拉通路起点,另一个必为欧拉通路的终点。
1.判断欧拉路是否存在的方法
有向图:图连通,有一个顶点:出度=入度+1,有一个顶点:入度=出度+1,其余都是出度=入度。
无向图:图连通,只有两个顶点是奇数度,其余都是偶数度。
2.判断欧拉回路是否存在的方法
有向图:图连通,所有的顶点出度=入度。
无向图:图连通,所有顶点都是偶数度。
用DFS判断图是否连通
#include<bits/stdc++.h>
using namespace std;
#define maxn 1005
#define inf 0x3f3f3f3f
int n,m;
vector<int> G[maxn];
bool vis[maxn];//标记节点是否遍历过
int degree[maxn];//记录节点的度
void dfs(int point)//深度优先搜索每个点
{
vis[point]=1;//标记访问过
for(int i=0;i<G[point].size();i++)//遍历所有与当前点相邻的点
{
int next=G[point][i];
if(!vis[next])//如果没有访问过
dfs(next);//继续访问
}
}
int main()
{
while(scanf("%d",&n)!=EOF&&n){
scanf("%d",&m);
for(int i=1;i<=n;i++)
G[i].clear();//多组测试,一定要清空
memset(vis,0,sizeof(vis));
memset(degree,0,sizeof(degree));
while(m--){
int u,v;
scanf("%d%d",&u,&v);
degree[u]++;//节点度数+1
degree[v]++;
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1);
bool flag=0;
for(int i=1;i<=n;i++)
if(!vis[i]){//如果存在节点没有访问过,则图不连通
flag=1;break;
}
if(flag)
printf("0\n");
else{
flag=0;
for(int j=1;j<=n;j++)
if(degree[j]&1)//奇数
{//存在某个点的度数为奇数,则不是欧拉回路
flag=1;
break;
}
if(flag) printf("0\n");
else printf("1\n");
}
}
return 0;
}
用并查集来判断图是否连通
#include<bits/stdc++.h>
using namespace std;
#define maxn 1005
#define inf 0x3f3f3f3f
int n,m;
int pre[maxn];//标记每个节点的前驱
int degree[maxn];//每个节点的度
int findset(int x)//寻找前驱
{
if(pre[x]==x)
return x;
return pre[x]=findset(pre[x]);//压缩路径
}
void unionset(int x,int y)//合并两个连通分量
{
int fx=findset(x),fy=findset(y);
pre[fx]=fy;
}
int main()
{
while(scanf("%d",&n)!=EOF&&n){
scanf("%d",&m);
for(int i=1;i<=n;i++)
pre[i]=i;//初始化前驱为自己
memset(vis,0,sizeof(vis));
memset(degree,0,sizeof(degree));
while(m--){
int u,v;
scanf("%d%d",&u,&v);
degree[u]++;//度数+1
degree[v]++;
unionset(u,v);
}
bool flag=0;
int father=findset(1);//根节点
for(int i=2;i<=n;i++)
if(findset(i)!=father){//存在其他根节点
flag=1;break;//则图是不连通的
}
if(flag)
printf("0\n");
else{
flag=0;
for(int j=1;j<=n;j++)
if(degree[j]&1)//奇数
{
flag=1;
break;
}
if(flag) printf("0\n");
else printf("1\n");
}
}
return 0;
}