欧拉回路

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
解题报告:
具体dfs,bfs可详见http://blog.csdn.net/scarlett_geng/article/details/47397521
这个题是我学习搜索之后写的第一个dfs的问题,用了将近两个半天的时间调的吧,自己完整的敲了三遍,出的问题比较多,还有代码风格注释的问题,学的东西也算是比较多的所以想写一下。
这个题了解了dfs和欧拉回路的概念之后,并不是很难,首先这个题肯定是一个无向图,而判断无向图是否有欧拉回路,有两个判断条件,一个是是否是连通图(可以用并查集和普通方法判断,这里先用普通方法),即从第一个点开始遍历,每遍历一个点ans++,结束后判断ans是否等于全部的点n,如果等于,即是连通的。第二个条件是判断是否每个点的度数都为偶数。这个一定要特别注意,一开始5210和我都sb了,没有想到一个点可能有多条边,直接写成了读到一个点后mp[i][j]=1,mp[j][i]=1,然后到了判断度的时候就直接degree++,所以这是一个问题,竟然一直没有先到(这里还是想吐槽一下看来我还是不太适合去当测试员,一般特殊情况很难想到orz)。所以这里应该是mp[i][j]++,mp[j][i]++,degree+=mp[i][j]。
然后有向图的判断就是是不是联通的,入度是否等于出度。
在dfs里面写的时候最初的时候忘记了ans++,每次判断一次ans都要++,这样最后才可以==n。
输出的时候记得第二个情况不符合条件的话也要输出的,而我第一次没有写= =。
最后要注意一下输入的格式处理,第一个如果为0,就直接退出了,所以不能直接输入两个,要输入第一个就判断,这是while(1)的用法。。
总的来说。。注意的地方还是很多的。。革命仍在继续。。以后仍需努力。。
上一下千疮百孔的代码。。
#include<cstdio>
#include<cstring>
using namespace std;
#define MAXN 1000+10
int m,n,mp[MAXN][MAXN],vis[MAXN];//全局变量默认就为0,所以这里不用设初始值为0 
int ans;  //ans因为两个函数都要用到,所以设成全局变量 
//dfs
void dfs(int u)
{
	vis[u]=1;
	for(int i=1;i<=n;i++)
	{
		if(vis[i]==0&&mp[u][i])
		{
			dfs(i);  //这个时候已经遍历了第一个点了,所以不能直接ans++了,要先dfs,再自增 
			ans++;
		}
	}
}
//判断是否连通 
int judge()  //只要从第一个点开始遍历,遍历到n个点就可以,不用加循环每个都遍历了 
{
	ans=1;
	if(!vis[1])
	dfs(1);
	if(ans==n)
		return 1;
	else
		return 0;	
}

int main()
{
	int a,b,degree,flag=0;
	//虽然是看似是两个数据的输入,
	//但是如果n==0的话,就直接停止了,所以不可以两个一起输入,
	//要先判断第一个输入的不为0的时候,再输入第二个数
	while(1)
	{
		scanf("%d",&n);
		if(n==0)
		break;
		scanf("%d",&m);
		memset(vis,0,sizeof(vis));  //每个要用到的数据一定要初始化,这个总是容易忽略 
		memset(mp,0,sizeof(mp));
		flag=0; 
		int c=0;
		for(int i =0;i<m;i++)
		{
			scanf("%d %d",&a,&b);
			mp[a][b]++;   //这里一开始写的是mp[][]=1,因为以为一个点只可以连接一条边,是个bug。可以一个点连多个边的 
			mp[b][a]++;
		}
		for(int i = 1;i<=n;i++)  //这里i=1,j=2 和i=2,j=1是不一样的,
		//因为是要算每个结点的度数,所以每个点都要遍历所有的和它相连的边 
		{
			degree=0;
			for(int j= 1;j<=n;j++)    //内循环不能写成i+1 
			{
				if(mp[i][j])  //这里和上面一样,只要不是0就行 
				degree+=mp[i][j];  //degree就不是自增了,要加上所有边的值 
			}
			if(degree%2!=0)
			{
				flag=1;
				break;
			} 
		}
		//printf("%d",flag);
		if(flag==1)
		{
			printf("0\n"); //这里不要写break,否则就所有跳出了。要用continue直接输入下一组数据
			continue;    //这个地方wa了两次,然后测数据的时候发现当flag==1的时候不输出结果,后来让它输出中间变量之后才发现这里先要printf,再continue 
		}
		c= judge();
		if(c==1&&flag==0)
		printf("1\n");
		else
		printf("0\n"); //不可以这一步不要了 ,因为也可能是第二个条件不满足 
	}
	return 0;
}


你可能感兴趣的:(HDU,DFS)