//
小希的迷宫
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 38688 Accepted Submission(s): 11861
Problem Description
上次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
#include<stdio.h>
#include<string.h>
#include<iostream>
/**
小希的迷宫
*/
using namespace std;
int set[10001];
int sign[10001];//因为要保证没有回路,所以需要另外设定一个数组标记出现在数字保证只有一个回路
int k=0; //判断是否存在回路 存在回路 k=1,不存在k=0
int count=0; //记录每次输入的次数
int x=0,y=0; //x存储根节点, y判断是否是同一个集合
void init() //初始化数组 将数组中的每个元素分为一个集合
{
for(int i=0;i<10001;i++)
{
set[i]=i;sign[i]=0;
}
}
int find(int i){
return set[i]==i?i:set[i]=find(set[i]); //路径压缩 使每个元素都指向一个根结点
}
bool check(int a,int b){ //检查图中是否存在回路
if(find(a)==find(b))
return false;
else return true;
}
void merge(int a,int b)
{
if(check(a,b)){
if(set[a]>set[b]) //保证 每个点都序连接 防止出现 eg:2 5 ,2连 5 ,2 3, 2连 3 会导致2连5的这条线丢失
set[b]=a; //将a集合指向b
else
set[a]=b;
}
else{
k=1;
}
}
//要保证每个点都是联通的
int main(){
int a,b; //输入的两个数据
int c=0;
while(scanf("%d%d",&a,&b)!=EOF){
init();
if(a==-1&&b==-1) break;
if(a==0&&b==0) //当直接输入0 0时 直接输出yes
{
printf("Yes");
continue;
}
c=a;
sign[a]=1;
sign[b]=1;
merge(a,b);
for(int i=0;;i++)
{
scanf("%d%d",&a,&b);
if(a!=0&&b!=0){//都等于0的时候不计数
merge(a,b);
count++;
sign[a]=1;
sign[b]=1;
}
if(a==0&&b==0){//输入0的时候跳出循环继续下一次输入
if(k==0){//不存在回路
x=set[c];//因为路径压缩,每个点的根节点都会一样
for(int i=1;i<=count;i++)//判断是否只存在一个集合 因为存在有点独立 没有完全联通
{
if(sign[i]&&set[i]!=x) { //只有满足sign[i}出现过的数据 才进行判断
if(find(i)==x) continue;
count=0;
y=1;
break;
}
}
if(y==0)
{
printf("Yes\n");
count=0;
x=0;
y=0;
break;
}
else{
printf("No\n");
count=0;
x=0;
y=0;
break;
}
}
else if(k==1){ //存在回路
k=0;//将k初始化
printf("No\n");
break;
}
}
}
}
return 0;
}
本题思路:
就是就迷宫中的点转换为图是否连通
1.连通的图要保证不存在回路,
2。连通的图只能有一个(只应该有一个集合)
#include<bits/stdc++.h>
#define maxsize 10001
int set[maxsize];
int biaoji[maxsize];
bool huilu;
int num=0;
void init(){ //并查集常用模板初始化将每个点化为一个集合
for(int i=0;i<maxsize;i++){
set[i]=i;
biaoji[i]=0;
}
}
int find(int i){ //查询路径压缩(将顶点所指向的最终母结点返回,保证查询效率)
return set[i]==i?i:set[i]=find(set[i]);
}
void merge(int a,int b){ //合并集合 如果最终的结点不同,则进行合并
biaoji[a]=1; //标记这个元素已经出现 ((题中存在的顶点)
biaoji[b]=1; //
if(find(a)==find(b)) //查找的时候最终母结点相同 此时合并 就会存在回路
huilu=true;
//find(a)>find(b)?set[b]=set[a]:set[a]=set[b]; //1->2 1->5 (不判断就会造成2-!>5)2无法连到5
set[find(a)]=find(b); //连接的时候只用使判断的母结点进行相连
}
void setNum(){ //查询合并后还有多少个集合 当集合中的最终母结点(数组的值)与顶点(数组的下标)相同
//则表示一个集合
for(int i=0;i<maxsize;i++){
if(set[i]==i&&biaoji[i]==1) //只对标记的元素进行判断(题中存在的顶点)
num++;
}
}
int main(){
int n,m;
while(~scanf("%d%d",&n,&m)!=EOF){
init();
huilu=false;
num=0;
if(n==-1&&m==-1)
break;
if(n==0&&m==0)
printf("Yes ");
else{
merge(n,m);
for(int i=0;;i++){
scanf("%d%d",&n,&m);
if(n==0&&m==0){
setNum();
if(huilu==false&&num==1)
printf("Yes ");
else
printf("No ");
break;
}else{
merge(n,m);
}
}
}
}
return 0;
}