写了好几道判断树的题目了,都是用极光的并查集来做的,归纳一下!

zl 发表于 2006-05-09 22:27:00

具体题目
//hdoj小系的迷宫
//zoj Is it a tree
//zoj message system

题目虽然有点不同,但都用到了相同并查集, 以及树的定义来判断
用并查集, 就是每次都新加一个节点,然后把它归到已有的节点集合中去, 假如每次都能合并成功(前提是读入这条边的两个节点还未在已有集合中连通,假如连通,则可以判断存在环,因为树中的点只能被连通一次, 即入度为1.)
这样就可以判断他是个无环图,  然后在按照树的定义来判断它的连通就ok了

同样,也可以用宽搜来达到证明图连通的目的,但是同样要借助树的定义来判断它是否存在环.
树的定义: node  =  edge + 1

//并查集(rights reserved by JGShining)


/*
适用范围:集合中元素范围是[1..MAXN]
*/

#include<stdio.h>
#include<memory.h>

#define MAXN 100000
int p[MAXN + 1], r[MAXN + 1];

// 初始化数据结构
void init_set()
{
   memset(p, 0, sizeof(p));
}

// 生成一个新的集合,其中只含有一个元素e
void make_set(int e)
{
   p[e] = e;
   r[e] = 0;
}

// 返回0表示并查森林中找不到该元素
int find_set(int key)
{
   if(key != p[key]) p[key] = find_set(p[key]);
   return p[key];
}

// 合并两个集合s1和s2,以rank大的作为根
void union_set(int s1, int s2)
{
   int p1, p2;
   if(s1 == s2) return;
   p1 = find_set(s1);
   p2 = find_set(s2);
   if(p1 != p2)
   {
       if(r[p1] > r[p2]) p[p2] = p1;
       else if(r[p2] > r[p1]) p[p1] = p2;
       else
       {
           r[p1]++;
           p[p2] = p1;
       }
   }
}

注意,在实现有向树的过程中,合并集合的方法必须是把弧顶节点合并到弧尾节点,就是说,把子节点合并到根节点



最新评论

发表评论

*昵称

已经注册过? 请登录

Email
网址
*评论