hdu 1272 小希的迷宫(并查集)

hdu 1272 小希的迷宫

http://acm.hdu.edu.cn/showproblem.php?pid=1272

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

题目大意:小希要做一个迷宫,迷宫中任意两个房间有且仅有一条路径可以相通(除非走了回头路)。

这样,就需要用到并查集了(赤裸裸的),对于输入的两个顶点,判断是否在同一个集合内,是的话,就是存在多条通路了,而对于一个迷宫,所有的点最后必须在同一个集合内(这一个问题刚开始没有考虑到,贡献了两次WA),处理好这两个问题,就可以了

有一个比较特殊的情况,就是输入的那一组数据只有两个0,必须输出 Yes

网上有很多人写了这个题目的解题报告,但大家都是用一个数组来记录是否用过,然后对用过的点进行寻根,最后看一下是不是所有有用过的点都是同一个根,我觉得没有必要,只要记录点是否用过,最后,连接的边和用到的点的差是1就可以了,也就是说连接n个点,只要n-1条边,so~~

#include<iostream>
using namespace std;
#define MAX 100001
bool mark[MAX];
int parent[MAX];
int findp(int a)
{
 while(a!=parent[a])
  a=parent[a];
 return a;
}

bool merge(int a,int b)
{
 int x=findp(a);
 int y=findp(b);
 if(x==y)
  return 0;
 parent[y]=x;
 return 1;
}
int main()
{
 int x,y;
 while(~scanf("%d%d",&x,&y))
 {
  if(!x&&!y)
  {
   puts("Yes");
   continue;
  }
  if(x==-1&&y==-1)
   break;
  int i;
  for(i=1;i<MAX;i++)
   parent[i]=i;
  memset(mark,0,sizeof(mark));
  mark[x]=mark[y]=1;
  merge(x,y);
  int n=1,flag=1;
  while(~scanf("%d%d",&x,&y))
  {
   if(!x&&!y)
    break;
   if(!mark[x])
   {
    n++;
    mark[x]=1;
   }
   if(!mark[y])
   {
    n++;
    mark[y]=1;
   }
   if(merge(x,y))
    n--;
   else
    flag=0;
  }
  if(flag&&n==1)
   puts("Yes");
  else 
   puts("No");
 }
 return 0;
}

我觉得广搜也可以 不过效率明显没有第一种高 不过还是贴一下我的代码

思路:当广度搜索到一个搜索过了的点,并且不是父亲结点时,就是个环

#include<iostream>
#include<vector>
#include<queue>
using namespace std;
vector<int> v[100001];
int parent[100001];
int bfs(int pos)
{
    queue<int> q;
    q.push(pos);
    int d,i;
    for(i=1;i<=100000;i++)
        parent[i]=i;
    parent[pos]=-1;
    while(!q.empty())
    {
        d=q.front();
        q.pop();
        for(i=0;i<v[d].size();i++)
        {
            if(v[d][i]==parent[d])
                continue;
            if(parent[v[d][i]]==v[d][i])
            {
                parent[v[d][i]]=d;
                q.push(v[d][i]);
            }
            else
                return 0;     
        }
    }
    return 1;
}
int findp(int a)
{
    while(a!=parent[a])
        a=parent[a];
    return a;
}
int main()
{
    int x,y,i;
    while(~scanf("%d%d",&x,&y))
    {
        if(x==-1&&y==-1)
            break;
        for(i=1;i<100001;i++)
            v[i].clear();
        int pos=x;
        v[x].push_back(y);
        v[y].push_back(x);
        if(!x&&!y)
        {
            puts("Yes");
            continue;
        }    
        for(i=1;i<=100000;i++)
            parent[i]=i;
        parent[y]=x;
        int xx,yy;
  int mark[100001]={0};
  mark[x]=mark[y]=1;
        int num=2;
  if(x==y)
   num=1;
        while(1)
        {
            scanf("%d%d",&x,&y);
            if(!x&&!y)
                break;
            v[x].push_back(y);
            v[y].push_back(x);
            xx=findp(x);
            yy=findp(y);
            if(xx!=yy)
                parent[yy]=xx;
            if(!mark[x])
   {
    num++;
    mark[x]=1;
   }
   if(!mark[y])
   {
    num++;
    mark[y]=1;
   }
        }
        int count=0;
        for(i=1;i<=100000;i++)
            if(parent[i]!=i)
                count++;
        if(count!=num-1)
        {
            puts("No");
            continue;
        }
        if(bfs(pos))
            puts("Yes");
        else
            puts("No");
    }
    return 0;
}

原文地址:https://www.cnblogs.com/crazyapple/p/2999457.html