小希的迷宫

上次Gardon的迷宫城堡小希玩了很久(见Problem B),现在她也想设计一个迷宫让Gardon来走。但是她设计迷宫的思路不一样,首先她认为所有的通道都应该是双向连通的,就是说如果有一个通道连通了房间A和B,那么既可以通过它从房间A走到房间B,也可以通过它从房间B走到房间A,为了提高难度,小希希望任意两个房间有且仅有一条路径可以相通(除非走了回头路)。小希现在把她的设计图给你,让你帮忙判断她的设计图是否符合她的设计思路。比如下面的例子,前两个是符合条件的,但是最后一个却有两种方法从5到达8。 
 
Input
输入包含多组数据,每组数据是一个以0 0结尾的整数对列表,表示了一条通道连接的两个房间的编号。房间的编号至少为1,且不超过100000。每两组数据之间有一个空行。 
整个文件以两个-1结尾。 
Output
对于输入的每一组数据,输出仅包括一行。如果该迷宫符合小希的思路,那么输出"Yes",否则输出"No"。 
Sample Input
6 8  5 3  5 2  6 4
5 6  0 0

8 1  7 3  6 2  8 9  7 5
7 4  7 8  7 6  0 0

3 8  6 8  6 4
5 3  5 6  5 2  0 0

-1 -1
Sample Output
Yes
Yes
No

这道题类似之前那个通信工程的题目

但是有一个问题是只输入0 0时,输出Yes

顶点与边的关系解法:

#include<cstdio>
#include<string.h> 
void Union(int a,int b);  
void p(int a);  
int find(int a);  
int pre[100010]={0};
bool reco[100010],root[100010];
int main()
{
	int m,n;
	while(scanf("%d%d",&m,&n)!=EOF) 
	{
		if(m==-1&&n==-1)
			break;
		else if(m==0&&n==0)
			printf("Yes\n");
		else
		{
			int i,j,flag,max,cnt,sum;
			cnt=0,sum=0,flag=0,i=0;
			memset(pre,0,sizeof(pre));
			memset(reco,0,sizeof(reco));
			memset(root,0,sizeof(root));
			p(100000);
			if(m>n)
				max=m;
			else
				max=n;
			if(m!=n)
				i++;
			reco[m]=true;
			reco[n]=true;
			Union(m,n);
			while(1)
			{
				scanf("%d%d",&m,&n);
				if(m>max)
					max=m;
				if(n>max)
					max=n;
				if(m==0&&n==0)
					break;
				else
				{
					if(m!=n)
						i++;
					reco[m]=true;
					reco[n]=true;
					Union(m,n);
				}
			}
			for(j=0;j<=max;j++)
			{
				if(reco[j])
					cnt++;
			}
			if(i!=cnt-1)
			{
				printf("No\n");
			}
			else
			{
				for(i=1;i<=max;i++)
				{
					root[find(i)]=true;
				}
				for(i=1;i<=max;i++)
				{
					if(reco[i])
					{
						if(root[i])
							sum++;
					} 
				}
				if(sum!=1)
					printf("No\n");
				else
					printf("Yes\n");
			}
		}
	}
	return 0;
}
void p(int a)  
{  
    int i;  
    for(i=0;i<a;i++)  
    {  
        pre[i]=i;  
    }     
}
void Union(int a,int b)  
{  
    int fa,fb;  
    fa=find(a);  
    fb=find(b);  
    if(fa!=fb)  
        pre[fb]=fa;  
}  
int find(int a)  
{  
    int r;  
    r=a;  
    while(r!=pre[r])  
    {  
        r=pre[r];  
    } 
	while(r!=pre[a])
	{
		int z;
		z=a;
		a=pre[a];
		pre[z]=r;
	} 
    return r;  
}   
检查是否有圈:

#include<cstdio>
#include<string.h>
void pn(int a);
void merge(int a,int b);
int find(int a);
int pre[100010];
bool root[100010],reco[100010];
int main()
{
	int m,n;
	while(1)
	{
		scanf("%d%d",&m,&n);
		if(m==-1&&n==-1)
			break;
		else if(m==0&&n==0)
			printf("Yes\n");
		else
		{
			int max,flag,i,cnt;
			flag=0,cnt=0;
			memset(pre,0,sizeof(pre));
			memset(root,0,sizeof(root));
			memset(reco,0,sizeof(reco));
			pn(100010);
			reco[m]=true;
			reco[n]=true;
			if(m>n)
				max=m;
			else
				max=n;
			merge(m,n);
			while(1)
			{
				scanf("%d%d",&m,&n);
				if(m==0&&n==0)
					break;
				else
				{
					if(m>max)
						max=m;
					if(n>max)
						max=n;
					reco[m]=true;
					reco[n]=true;
					if(find(m)==find(n))
						flag=1;
					merge(m,n);
				}
			}
			if(flag)
				printf("No\n");
			else
			{
				for(i=1;i<=max;i++)
				{
					if(reco[i])
						root[find(i)]=true;
				}
				for(i=1;i<=max;i++)
				{
					if(reco[i])
					{
						if(root[i])	
							cnt++;
					}					
				}
				if(cnt==1)
					printf("Yes\n");
				else
					printf("No\n");
			}
		}
	}
}
void pn(int a)
{
	int i;
	for(i=0;i<a;i++)
	{
		pre[i]=i;
	}
}
void merge(int a,int b)
{
	int fa,fb;
	fa=find(a);
	fb=find(b);
	if(fa!=fb)
	{
		pre[fb]=fa;
	}
}
int find(int a)
{
	int r,z;
	r=a;
	while(r!=pre[r])
	{
		r=pre[r];
	}
	while(a!=pre[a])
	{
		z=a;
		a=pre[a];
		pre[z]=r;
	}
	return r;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值