查看题目https://cn.vjudge.net/contest/243676#problem/M
此题不仅仅是判断 是否构成环, 如果不构成环 还要进一步判断 是森林还是树
首先先判断是否构成环
在合并a,b之前, 先判断a,b的根节点是否相同 , 如果合并之前a,b的根节点相同, 则构成环(都还没合并呢, 根节点就相同了,那合并之后不是环那还是啥)
如果不构成环, 进一步判断 是树还是森林
根据树 和 森林的区别, 树的节点总数 总比 边大1, 即 节点(v)-边(e) ==1 , 森林可没这个性质!!
这里面有个坑需要注意: 如果一开始输入两个0 , 则输出"Yes" , 这里我现在也没搞懂
代码
#include<iostream>
#include<cstdio>
using namespace std;
const int MAX = (int)1e5 + 5;
int per[MAX], flag[MAX],is;
int find(int x)
{
int r = x;
while (r != per[r])
r = per[r];
int i = x, j;
while (i != r)
{
j = per[i];
per[i] = r;
i = j;
}
return r;
}
void join(int x, int y)
{
int fx = find(x), fy = find(y);
if (fx != fy)
per[fx] = fy;
}
int main()
{
int a, b;
while (scanf("%d%d", &a, &b) != EOF)
{
if (a == -1 && b == -1) break;
else if (a == 0 && b == 0)
{
cout << "Yes" << endl; //这就是我说的坑
continue;
}
is = 0;//无环
int v = 0, e = 1;//顶点和边
for (int i = 1; i <= MAX; ++i)
{
per[i] = i; flag[i] = 0;
}
flag[a] = flag[b] = 1;//该点存在
join(a, b);
while (scanf("%d%d", &a, &b) != EOF, a || b)
{
e++;
flag[a] = flag[b] = 1; //标记哪些点出现过
if (find(a) == find(b))// 合并之前如果根节点相同
is = 1;//存在环
else join(a, b);
}
if (is==1)//如果是环
{
cout << "No" << endl;
}
else//如果不是环 进一步判断是树 还是森林
{
for (int i = 1; i <= MAX; ++i)
if (flag[i]==1) v++; //统计节点的个数
if (v - e == 1) //是树
cout << "Yes"<< endl;
else cout << "No" << endl; //是森林
}
}
return 0;
}