您的位置:首页 > 其它

HDU-1325-Is It A Tree?

2012-08-26 12:01 274 查看
题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1325

程序分析:

  这道题跟小希的迷宫有很大的相似吧,只是一个是无向图一个是有向图。也是给你那些结点之间的信息,然后让你判断是不是一颗树罢了,用树的定义来判断吧,无环,n个结点最多有n-1条边,不然就会有环。只有一个入度为0的结点,不存在入度大于1的结点。这些也足以判断是否为一棵树了吧。不过要注意一些特殊数据的情况,空树也是树。比如输入0 0。

解决方法:

  其实也可以不用并查集,这样就可以直接按照上面的条件来统计,就可以判断是不是一颗树了。方法有多种,都知道最好,但是得精通,这些天都是在练并查集,所以我就用了并查集的思想来做吧,我加了个条件判断就是判断他村不存在环,这个是用到:如果两个不同的结点的根结点都相同,这样就会存在一个环或者有一个结点的入度会变为2了。只好也就不符合树的定义了。

  控制输入数据时有点坑爹,输入停止条件应该是 a < 0 || b < 0,因为这个WA了很多次,最后是老大帮我改了之后就A了,一直还以为是数组不够大或者输入函数那些没写好,原来就是这么一个小BUG。学东西吧,错的多,改对了就能学会多一点。

View Code

#include<iostream>
using namespace std;

const int Max = 100000+10;
int Far[Max];
int Rank[Max]; //改为标记结点的入度
int Sign[Max];

void Make_set(int n)
{
int i;
for(i=0; i<n; i++)
{
Far[i] = i;
}
memset(Rank, 0, sizeof(Rank));
memset(Sign, 0, sizeof(Sign));
}

int Find_set(int x)
{
if(Far[x] != x)
return Far[x] = Find_set(Far[x]);
return Far[x];
}

void Unio(int a, int b)
{
a = Find_set(a);
b = Find_set(b);
if(a == b)
return;
//因为是有向图,合并方向必须只有一个
Far[b] = a;
/*
if(Rank[a] < Rank[b])
Far[a] = b;
else if(Rank[a] > Rank[b])
Far[b] = a;
else
{
Far[a] = b;
Rank[b]++;
}*/
}

int main()
{
int a, b;
//初始化
int flag = 1;
int k = 1;
Make_set(Max);
while(cin>>a>>b )
{
if(a < 0 || b < 0)
return 0;
if(a == 0  && b == 0) //待一组数据输入完毕后才输出结果
{
int ans = 0;
for(int i=1; i<Max; i++)
{
if(Sign[i] && Find_set(i) == i)  //统计有几个连通分支
ans++;
if(Rank[i] > 1)  //存在有入度大于一的结点就不是树了,是图
{
flag = 0;
break;
}
}
if(ans > 1)  //连通分支大于1,表示是否为森林
flag = 0;
if(flag)
cout<<"Case "<<k++<<" is a tree."<<endl;
else
cout<<"Case "<<k++<<" is not a tree."<<endl;
//从新初始化
flag = 1; //表示为Yes
Make_set(Max);
continue;
}
if(a != b && Find_set(a) == Find_set(b))  //根节点相同,但叶子不同,表示a,b已存在路径,如果
{                                          //仍增加一条路径则会存在环,则有第二天路径
//cout<<"No"<<endl;
flag  = 0;
}
else
{
Sign[a] = 1;
Sign[b] = 1;
Rank[b] ++;  //入度加一
Unio(a, b);  //b的老大是a,只能是一个方向,因为是有向图
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: