题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=1272
AC代码+解释
//并查集
//用并查集来判断是否出现环 (若两个顶点原本就在一条集合中,现在又输入这两个顶点(就是在这两个顶点之间加边)),则可知形成环)
AC代码+解释
//并查集
//用并查集来判断是否出现环 (若两个顶点原本就在一条集合中,现在又输入这两个顶点(就是在这两个顶点之间加边)),则可知形成环)
//判断是否连通 (遍历所有点是看否在同一集合, 若不止一个集合则表示不连通)
#include<bits/stdc++.h>
using namespace std;
#define MAX_N 100005
int mark[100000]; //用来标记是否出现这个数(下标表示这个数) 如果有则标记为1 没有则是 0 为后面遍历所有的数做准备
int par[MAX_N]; //父亲
int rank1[MAX_N]; //树的高度
//初始化n个元素
void init(int n)
{
for (int i = 0; i < n; i++)
{
par[i] = i;
rank1[i] = 0;
}
}
//查询树根
int find(int x)
{
if (par[x] == x) return x;
else return par[x] = find(par[x]);
}
//合并x和y所属的集合
void unite(int x, int y)
{
x = find(x);
y = find(y);
if (x == y) return;
if (rank1[x] < rank1[y]) par[x] = y;
else
{
par[y] = x;
if (rank1[x] == rank1[y])
rank1[x]++;
}
}
//判断x和y是否属于同一个集合
bool same(int x, int y)
{
return find(x) == find(y);
}
//主函数
int main()
{
int a, b;
int ok = 1; //ok 等于 1 表示 最后输出Yes
while(scanf("%d%d",&a,&b))
{
ok = 1;
init(100002); //初始化
memset(mark, 0, sizeof(mark));
int Max = -1000010, Min = 1000010; //求出输入点的最大值和最小值 (为最后遍历所有数确定边界)
if (a == 0 && b == 0) //特殊情况
{
printf("Yes\n");
continue;
}
if (a == -1 && b == -1)
break;
unite(a, b); //将a和b 合并
int n, m;
Max = max(max(a, Max), b); //表示最大值 此处是为后面将所有的数遍历一遍做准备
Min = min(min(a, Min), b); //表示最小值
mark[a] = mark[b] = 1;
while(scanf("%d%d",&n,&m))
{
if (n == 0 && m == 0) break;
Max = max(max(n, Max), m); //表示最大值 此处是为后面将所有的数遍历一遍做准备
Min = min(min(n, Min), m); //表示最小值
mark[n] = mark[m] = 1;
if (same(n, m)) //表示有环 因为他们两个原本就在一个 集合中,又加了一条边就形成了环
ok = 0; //表示最后输出No 表示不通过
else unite(n, m); //将两个元素合并
}
//将所有的数遍历一遍 看所有的点是否都在一个集合中 如果有不在一个集合 则不符合
for (int i = Min+1; i <= Max; i++)
{
if (mark[i] == 1)
{
if (!same(Min, i)) ok = 0; //表示这两个元素不在一个集合 表示不成立
}
}
if (ok)printf("Yes\n");
else printf("No\n");
}
return 0;
}
本文介绍了一个使用并查集实现的算法,该算法可以有效地判断图中是否存在环,并验证图是否完全连通。通过对每一对顶点进行合并操作,并检查是否有重复的合并尝试来发现环。此外,还通过遍历所有顶点确认它们是否属于同一集合来确保图的连通性。
537

被折叠的 条评论
为什么被折叠?



