ACM-并查集模板+做题记录

8 篇文章 0 订阅
7 篇文章 0 订阅
#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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值