#define N 105
int pre[N]; //每个结点
int rank[N]; //树的高度
//初始化
int init(int n) //对n个结点初始化
{
for(int i = 0; i < n; i++){
pre[i] = i; //每个结点的上级都是自己
rank[i] = 1; //每个结点构成的树的高度为1
}
}
int find_pre(int x) //查找结点x的根结点
{
if(pre[x] == x){ //递归出口:x的上级为x本身,即x为根结点
return x;
}
return find_pre(pre[x]); //递归查找
}
//改进查找算法:完成路径压缩,将x的上级直接变为根结点,那么树的高度就会大大降低
int find_pre(int x) //查找结点x的根结点
{
if(pre[x] == x){ //递归出口:x的上级为x本身,即x为根结点
return x;
}
return pre[x] = find_pre(pre[x]); //递归查找 此代码相当于 先找到根结点rootx,然后pre[x]=rootx
}
bool is_same(int x, int y) //判断两个结点是否连通
{
return find_pre(x) == find_pre(y); //判断两个结点的根结点(亦称代表元)是否相同
}
void unite(int x,int y)
{
int rootx, rooty;
rootx = find_pre(x);
rooty = find_pre(y);
if(rootx == rooty){
return ;
}
if(rank(rootx) > rank(rooty)){
pre[rooty] = rootx; //令y的根结点的上级为rootx
}
else{
if(rank(rootx) == rank(rooty)){
rank(rooty)++;
}
pre[rootx] = rooty;
}
}
做题记录:
畅通工程 HDU - 1232 (easy)
#include<bits/stdc++.h>
using namespace std;
int a[1000+7];
int root(int x)//查找根节点
{
if(a[x]==x)
{
return x;
}
return a[x]=root(a[x]);// 路径压缩(其实数据比较弱,压不压缩区别不大,自测都是15 ms跑完)
}
void unite(int x,int y)//合并
{
int fx=root(x);
int fy=root(y);
if(fx!=fy) a[fx]=fy;
}
void init()//预处理
{
for(int i=1;i<=1000;i++)
{
a[i]=i;
}
}
int main()
{
int n,m;
while(1)
{
init();
scanf("%d",&n);
if(n==0) break;
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
unite(x,y);
}
int ans=-1;
for(int i=1;i<=n;i++)
{
if(a[i]==i) ans++;//若某个点的父节点是自己,说明他是这一类中的代表,所以ans++计数。
}
printf("%d\n",ans);
}
return 0;
}
HDU-1272 小希的迷宫
思路: 要想符合要求,首先要是一个整体,不能分为多块,也就是判断联通块,方法和上一题一模一样,其次还要保证不能出现环,即合并的两个点的父节点相同的不能合并。
坑点:这题数据很坑,要考虑0 0这种空树,也要输出yes。 还有要考虑1 1这种自环,也要输出yes,所以碰到自环直接跳过(通过continue ,直接去读下一个数据,不再坐后面的操作),不然在后面合并的时候 两个相同点的父节点相同,必然会被认为是一个环,导致计数出现错误。
#include<bits/stdc++.h>
using namespace std;
int a[100000+7],vis[100000+7];
int yes=0,go=0,maxx=0,y=0;
int root(int x)
{
if(a[x]==x)
{
return x;
}
return a[x]=root(a[x]);
}
void unite(int x,int y)
{
int fx=root(x);
int fy=root(y);
if(fx!=fy) {a[fx]=fy;}
else yes=1;
}
void init()
{
for(int i=1;i<=100000;i++)
{
a[i]=i;
}
memset(vis,0,sizeof vis);
yes=0;go=0;maxx=0;y=0;
}
int main()
{
int x,y;
init();
while(1)
{
scanf("%d%d",&x,&y);
if(x==-1&&y==-1) break;
vis[x]=1;
vis[y]=1;
if(x>maxx||y>maxx){maxx=max(x,y);}
if(x==y&&x!=0) {continue;}
if(x==0&&y==0)
{
int ans=0;
for(int i=1;i<=maxx;i++)
{
if(a[i]==i&&vis[i]==1) ans++;
if(ans>=2) {printf("No\n");y=1;}
}
if(y==1){init();continue;}
if(go==1) printf("No\n");
else {printf("Yes\n");}
init();
continue;
}
unite(x,y);
if(yes==1) go=1;
}
return 0;
}