HDU1272 小希的迷宫 并查集
参考网址:http://blog.sina.com.cn/s/blog_6827ac4a0100nyjy.html
解题思路:
由于这里出现的数字不一定连续的数字都会出现,所以设一个mark来标记数字是否出现过。每次输入一对数字的关系则进行查找根结点的函数,即:
if(aa==bb)
{
flag=1;
}
如果能查找到根结点就证明二者已经是相通的,再输入二者的关系就变成有多条相通的路径了。如果不能查找到根结点则继续标记他们的关系。到一个数据输入结束后,再进行判断,是否输入的关系每个数字之间都有相通的路径,即:
for(i=min;i<=max;i++)
{
if(mark[i]&&set[i]==i)
cnt++;
}
if(cnt==1)
printf("Yes\n");
else
printf("No\n");
}
这里还有一个小注意:如果每测试数据已0 0输入,也应打印出Yes
参考代码:
#include<stdio.h>
#include<algorithm>
using namespace std;
int set[100010];
bool mark[100010];
int flag;
int find(int x)
{
    int r=x;
    while(set[r]!=r)
        r=set[r];
    return r;
}
void merge(int x,int y)
{
    int fx,fy;
    fx=find(x);
    fy=find(y);
    if(fx!=fy)
        set[fx]=fy;
}
//每次都是这两个函数的出现,
//就一个是寻找根节点的,还有一个是
//连接两个树的函数,过程相对复杂
//感觉自己是要牢记这两个函数了,无奈啊
int main()
{
    int a,b,i;
    while(scanf("%d%d",&a,&b)!=EOF)
//本题的输入还是采取一贯的模式作风,
//这个也是值得自己学习的东西的,
//不能因为输入格式的变而改变了自己的书写套路
    {
        flag=0;int cnt=0;
        if(a==-1&&b==-1)break;
        if(a==0&&b==0)
        {
            printf("Yes\n");
            continue;
        }
        for(i=0;i<100010;i++)
        {
            set[i]=i;
            mark[i]=0;
        }
//两个初始化,一个用来标记根节点,
//还有一个用来初始化为0
        int max=-1,min=100010;
        while(a||b)//当a,b均不为0时的标记
        {
            if(a>max)max=a;
            if(b>max)max=b;
            if(a<min)min=a;
            if(b<min)min=b;//将最大值和最小值都标记出来
            mark[a]=1;
            mark[b]=1;//当一个数有输入之后就选择将它打好标记
            int aa=find(a);
            int bb=find(b);
            if(aa==bb)
            {
                flag=1;
            }
//用来判断两个数是不是一组的,如果是的话就不进行操作了,
//如果不是那么我们就要选择让他们联通成为一棵树
            else
                merge(aa,bb);
            scanf("%d%d",&a,&b);
        }
        if(flag==1)
            printf("No\n");
        else
        {
            for(i=min;i<=max;i++)
            {
                if(mark[i]&&set[i]==i)
                   cnt++;
            }
            if(cnt==1)
                printf("Yes\n");
            else
                printf("No\n");
        }
    }
    return 0;
}
当然,这里还有一个非常相像的题目叫
hdu 1325 Is It A Tree?(并查集)
就是一个有向图和一个无向图的区别
代码
#include <stdio.h>
const int max_num = 100000+10;
 struct Node//Node
{
    int num,root,conn;//数据、根、入度
} node[max_num];//node[max_num];
//Node node[max_num];
void init()//这个应该算得上是一个初始化的函数了,值得参考
{
    for(int i = 0; i < max_num; i++)
    {
        node[i].conn = 0;//入度初始化为0
        node[i].root= i;//根记录为自身
        node[i].num=0;//标记数字是否被使用过,0:没有被使用过,1:使用过了
    }
}
int find_root(int a)//一个寻找根的函数,返回值是自己的根节点的值
{
    if(node[a].root!=a)
        return node[a].root = find_root(node[a].root);
    return node[a].root;
}
void union_set(int a,int b)//一个合并两棵树的函数,在两个节点不是同一个的时候使用
{
    a = find_root(a);
    b = find_root(b);
    if(a==b)//同一个根,说明是在同一个树下
    return;
    node[b].root=a;//把b的根赋为a的根,此时a已经是根,num==root
}
int main()
{
    int n,m;
    int i = 1;
    bool flag=true;//true:是个树,false:不是树
    init();
    while(scanf("%d%d",&n,&m)!=EOF&&n>=0&&m>=0)//当输入的值为-1时,循环结束
    {
        if(!flag&&n!=0&&n!=0)continue;//已经确定不是树了,就继续循环
        if(n==0&&m==0)
        {
            int root_num=0;
            for(int j = 1; j < max_num;j++)
            {
                //判断是否为森林,如果,root_num用来记录根的数目
                if(node[j].num && find_root(j)==j)//执行条件,被使用过而且还是根节点
                root_num++;
                if(node[j].conn>1)//如果出现某个节点的入度超过1,不是树。这个标记打的好
                {
                    flag = false;
                    break;
                }
            }
            if(root_num>1)//连通分支大于1,是森林不是树
                flag=false;
            if(flag)
            printf("Case %d is a tree.\n",i++);
            else printf("Case %d is not a tree.\n",i++);
            flag = true;
            init();
            continue;
        }
        if(m!=n&&find_root(n)==find_root(m))//而且操作是不能重复的
        flag = false;
        else
        {
            //将m,n,记录为节点
            node[m].num = 1;
            node[n].num = 1;
            node[m].conn++;//入度增加一
            union_set(n,m);
        }
    }
    return 0;
}
 
                    
                     
                    
                 
                    
                 
 
         
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号