寒假c语言学习

本文详细介绍了并查集算法的初始化、查询和合并操作,以及在解决P3367和P1111修复公路问题中的实际应用,展示了如何利用并查集判断环路并优化路径。
摘要由CSDN通过智能技术生成

并查集

操作一:初始化

用一个数组fa【】来储存每个元素的父节点,一开始将所有的元素的父节点设置为自己。

void 初始化(int n)
{
    for(int i=1;i<=n;i++)
    fa[i]=i;
}

操作二:查询

找父节点的父节点的......也就是祖先。

int find(int i)
{
    if(fa[i]==i)//找到了祖先直接返回
    return i;
    else{//没有找到就继续找
    return find(fa[i]);   
    }
}

但此时会发现如果父子连很长这时找到最下面的祖先就需要寻找很多次,就需要优化吧路径缩短:

int find(int i)
{
    if(fa[i]==i)
    {
        return i;
    }
    else{
        fa[i]=find(fa[i]);//插入这一步缩短路径
        return fa[i];
    }
}

操作三:合并

void unionn(int a1,int b1)
{
    int i,j;
    i=find(a1);
    j=find(b1);//找到两个元素的祖先
    fa[i]=j;//将i的祖先指向j的祖先,这样他们两就是一家人了
}

练习题:

P3367 【模板】并查集

P3367 【模板】并查集 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[10010];
void unionn(int a,int b);
int find(int i);
int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    a[i]=i;
    while(m--)
    {
        int z,x,y;
        cin>>z>>x>>y;
        if(z==1){
            unionn(x,y);
        }
        else{
            if(find(x)==find(y))cout<<'Y'<<endl;//有共同祖先说明已经被合并
            else cout<<'N'<<endl;
        }
    }
}
void unionn(int a1,int b1)
{
    int i,j;
    i=find(a1);
    j=find(b1);
    a[i]=j;
}
int find(int i)
{
    if(a[i]==i)
    {
        return i;
    }
    else{
        a[i]=find(a[i]);
        return a[i];
    }
}

P1111 修复公路

P1111 修复公路 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

主要思路:连接n个点最小路段只需要n-1条,先将所有路所需要的时间按从小到大排序,优先选取小时间的路段修路,修每条路时需要判断所修的路是否有环,有就是判断是否有共同的祖先,有环就不修。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct node {
    int x,y,t;
}a[100005];
int fa[100005];
void unionn(int a,int b);
int find(int i);
int compare(node a1,node b1);
int main()
{
    int n,m,i;
    cin>>n>>m;
    for(i=1;i<=n;i++)fa[i]=i;//初始化
    for(i=1;i<=m;i++)cin>>a[i].x>>a[i].y>>a[i].t;
    sort(a+1,a+m+1,compare);//排序
    int ans=a[1].t;
    for(i=1;i<=m;i++)
    {
        if(find(a[i].x)!=find(a[i].y))//判断是否有共同祖先,有闭环就会多余
        {
            unionn(a[i].x,a[i].y);//合并,通路
            ans=max(ans,a[i].t);//获取路的最大时间
            n--;
            if(n==1)cout<<ans<<endl;
        }
    }
    if(n!=1)cout<<-1;//不行就输出-1
}
void unionn(int a1,int b1)
{
    int i,j;
    i=find(a1);
    j=find(b1);
    fa[i]=j;
}
int find(int i)
{
    if(fa[i]==i)
    {
        return i;
    }
    else{
        fa[i]=find(fa[i]);
        return fa[i];
    }
}
int compare(node a1,node b1)
{
    return a1.t<b1.t;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值