并查集

实验七 并查集

Is It A Tree?(题目来源:poj1308)

Description

A tree is a well-known data structure that is either empty (null, void,nothing) or is a set of one or more nodes connected by directed edges betweennodes satisfying the following properties. 

There is exactly one node, called the root, to which no directed edgespoint. 

Every node except the root has exactly one edge pointing to it.

There is a unique sequence of directed edges from the root to each node.

For example, consider the illustrations below, in which nodes arerepresented by circles and edges are represented by lines with arrowheads. Thefirst two of these are trees, but the last is not. 

In this problem you will be given several descriptions of collections ofnodes connected by directed edges. For each of these you are to determine ifthe collection satisfies the definition of a tree or not.

Input

The input will consist of a sequence of descriptions (test cases) followedby a pair of negative integers. Each test case will consist of a sequence ofedge descriptions followed by a pair of zeroes Each edge description willconsist of a pair of integers; the first integer identifies the node from whichthe edge begins, and the second integer identifies the node to which the edgeis directed. Node numbers will always be greater than zero.

Output

For each test case display the line "Case k: is a tree." or theline "Case k: is not a tree.", where k corresponds to the test casenumber (they are sequentially numbered starting with 1).

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

0 0

1 2 1 2 0 0

1 2 3 2 0 0

1 1 0 0

1 2 2 1 0 0

1 2 2 3 4 5 0 0

-1 -1

Sample Output

Case 1: is a tree.

Case 2: is a tree.

Case 3: is not a tree.

Case 4: is a tree.

Case 5: is not a tree.

Case 6: is not a tree.

Case 7: is not a tree.

Case 8: is not a tree.

Case 9: is not a tree.

 

题意:给出一些节点的连接情况,问所给出的节点是不是可以构成一棵树(节点<100个)。树的定义如下:

1exactly onenode, called the root, to which no directed edges point.

2Every nodeexcept the root has exactly one edge pointing to it.

3There is aunique sequence of directed edges from the root to each node.

思路:并查集的应用。重点在于考虑情况要全,考察下述情形:

情况一:0 0  空树是一棵树

情况二:1 2 1 2 0 0  不是树,重复不行

情况二:1 2 3 2 0 0  不是树,不必解释吧

情况二:1 1 0 0  不是树,不能自己到自己有路径

情况二:1 2 2 1 0 0  也是错误的(环)

情况三:1 2 2 3 4 5  森林不是树

实验报告:

1、掌握并查集算法的特点,测试并验证。

2、提交实验报告,报告内容包括:目的、要求、算法描述、程序结构、主要变量说明、程序清单、调试情况、设计技巧、心得体会。

 

1:运行结果截图

2输入不说明有多少个测试用例,以特殊输入为结束标志,输出结果之前给出用例序号Case #:

……

int icase=1;

while(scanf("%d %d",&x, &y) != EOF) {

if(x== -1 && y == -1) break;

……

if(是树) printf("Case %d: is a tree.\n", icase++);

elseprintf("Case %d: is not a tree.\n", icase++);

}

 

3:并查集基本套路

// 创建集合:初始状态,每个元素都是一棵以自己为根的树(集合)

void make_set() {

intx;

for(x= 1; x < 100; x++) {

parent[x]= x;

//parent[x]:x所在集合的编号(所在树的根,初始自己就是根)

}

}

// 查找元素所在集合的编号(即所在树的根)

int find_set(int x) {

if(x!= parent[x])

parent[x]= find_set(parent[x]);

returnparent[x];

}

// 合并集合,并以第一个集合的编号(树根)作为合并后的集合编号(树根)

void union_set(int x, int y) {

x= find_set(x);

y= find_set(y);

if(x== y) return;

parent[y]= x;

}

 

特别说明,为适应题目要求,把union_set函数按如下改造:

void union_set(int x,int y) {

intv1,v2;

if(y!= parent[y]) {

tree= 0; // tree是一个标志,约定值为1时是树,值为0时不是树,最

//后的输出只需通过判断tree的值即可

return;

}

//上述判断的含义:如果结点编号不等于本身,说明之前已经有一条边指向

//它,可能和现在这条边重复,也可能不重复,不管何种情况都不能成为树

//解决上述第2种情况的前面两种可能

v1= find(x);

v2= find(y);

if(v1== v2) {

tree= 0;

return;

}

//两个点的根结点相等,说明形成了环或自己指向自己

//解决上述第2种情况的后面两种可能

parent[v2]= v1;

}

 

森林的提示:

如果是森林,则至少有一个结点的根和其它结点的根不一样,可按如下方式:

if(find(backup[0]) !=find(backup[i])) {

//backup数组用来保存输入的结点

//只需要判断第一个点是否和其它点在一个集合中即可,只要有一个点和第

//一个点不在一个集合中,即可判定为森林。为什么?

tree= 0;

….

}


代码如下:

#include<stdio.h>
int parent[100]={0};
int backup[100]={0};
int tree=1;
void make_set() 
{
int x;
for(x = 0; x < 100; x++) {
parent[x] = x;
// parent[x]:x所在集合的编号(所在树的根,初始自己就是根)
}
}


int find_set(int x) {
if(x != parent[x])
parent[x] = find_set(parent[x]);
return parent[x];
}




void union_set(int x,int y) {
int v1,v2;
if(y != parent[y]) {
tree = 0; // tree是一个标志,约定值为1时是树,值为0时不是树,最
// 后的输出只需通过判断tree的值即可
return;
}
// 上述判断的含义:如果结点编号不等于本身,说明之前已经有一条边指向
// 它,可能和现在这条边重复,也可能不重复,不管何种情况都不能成为树
// 解决上述第2种情况的前面两种可能
v1 = find_set(x);
v2 = find_set(y);
if(v1 == v2) {
tree = 0;
return;
}
// 两个点的根结点相等,说明形成了环或自己指向自己
// 解决上述第2种情况的后面两种可能
parent[v2] = v1;
}






int main()
{   int x,y;

int icase=1;
    //int tree=1;
make_set();
int i=0;
int num=0;
int j=0;
while((scanf("%d %d", &x, &y)) ) 
{
if(x == -1 && y == -1) break;
if(x==0 && y==0)
{

for(i=0;i<num;i++)
if(find_set(backup[0]) != find_set(backup[i]))
{
tree = 0;
}
if(tree) printf("Case %d: is a tree.\n", icase++);
else printf("Case %d: is not a tree.\n", icase++);
tree=1;
make_set();
for(i=1;i<=num;i++)
backup[i]=0;
j=0;
num=0;
continue;
}

union_set(x,y);
backup[j++]=x;
backup[j++]=y;
num+=2;

}
return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值