ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

20220724与佬谈并查集

2022-07-24 02:31:14  阅读:140  来源: 互联网

标签:shanzr 查集 int myFind 10010 20220724 fa include


听佬一席话,胜刷一周题。要抓住一切机会和佬尬聊啊hhh

起源

和佬的尬聊中,偶然提及了并查集。学了一周算法的\(shanzr\)自信地打出他最喜欢的板子:

int fa[10010];
int myFind(int x){while(x!=fa[x])x=fa[x]=fa[fa[x]];}
void myUnion(int a,int b){fa[myFind(a)]= myFind(b);}

很快啊,十来秒完事。

正当\(shanzr\)看着极致的压行洋洋自得时,大佬发问:

image

问题1 路径真的压缩了吗

\(shanzr\)根据看到的题解,不加思索地回答:这个就是优化掉了递归方法压缩路径,避免爆栈。

然后佬贴出了代码,大概是:

#include "iostream"
#include <bits/stdc++.h>
using namespace std;
int fa[10010];
int myFind(int x){while(x!=fa[x])x=fa[x]=fa[fa[x]];}

int main(){
    for(int i=2;i<=100;i++)fa[i]=i-1;//构造一个链,这是并查集搜索时最糟糕的情况
    fa[1]=1;
    myFind(100);//从100开始寻父
    for(int i=2;i<=100;i++)cout<<fa[i]<<" \n"[i%10];//打印父亲。如果真的路径压缩,那么fa应该压缩为1
}

打印结果为:

1 2 2 4 4 6 6 8 8 10
10 12 12 14 14 16 16 18 18 20
20 22 22 24 24 26 26 28 28 30
30 32 32 34 34 36 36 38 38 40
40 42 42 44 44 46 46 48 48 50
50 52 52 54 54 56 56 58 58 60
60 62 62 64 64 66 66 68 68 70
70 72 72 74 74 76 76 78 78 80
80 82 82 84 84 86 86 88 88 90
90 92 92 94 94 96 96 98 98

啊这,不太对劲。

再看看传统递归:

#include "iostream"
#include <bits/stdc++.h>
using namespace std;
int fa[10010];
int myFind(int x){
    if(x!=fa[x])
        return fa[x]= myFind(fa[x]);
}

int main(){
    for(int i=2;i<=100;i++)fa[i]=i-1;
    fa[1]=1;
    myFind(100);
    for(int i=2;i<=100;i++)cout<<fa[i]<<" \n"[i%10];
}

打印结果为:

1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1

这下知道谁厉害了QAQ

image

\(\rm orz\)实践出真知

另外还学了一手,注意到代码中的

for(int i=2;i<=100;i++)cout<<fa[i]<<" \n"[i%10];

" \n"[i%10]的结构就是string[index],其中string=" \n"index=i%10

合理使用这个语句,可以轻松处理换行。

问题2 有人秩都写错了,我不说是谁

根据一周所学,\(shanzr\)又想到了秩。或许有了秩,while循环的表现就会好很多?他信心满满,三两下捣鼓出来了一串\(\rm bug\)。

错误太蠢了就不放这了。贴一下正确的测试代码:

#include "iostream"
#include <bits/stdc++.h>
using namespace std;
int fa[10010];
int rk[10010];
int myFind(int x){while(x!=fa[x])x=fa[x]=fa[fa[x]];}
void myUnion(int x,int y){
    x=myFind(x),y=myFind(y);
    if(x==y) return ;
    if(rk[x]<=rk[y]) fa[x]=y;
    else fa[y] = x;
    if(rk[x]==rk[y]) rk[x]++;
}
int main(){
    fa[1]=1;
    for(int i=1;i<=100;i++)rk[i]=1;
    for(int i=2;i<=100;i++){
        myUnion(i-1,i);
    }
    myFind(100);//从100开始寻父
    for(int i=2;i<=100;i++)cout<<fa[i]<<" \n"[i%10];//打印父亲。如果真的路径压缩,那么fa应该压缩为1
}

打印结果:

1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1

好!

问题3 返回值?

还有一个问题,为啥myFind()不需要显式地return呢?

image

笨但勤快的\(shanzr\)开始测试,代码如下:

#include "iostream"
#include <bits/stdc++.h>
using namespace std;
int test1(){
    int a=100;
}
int test2(){
    int a=0;
    a+=100;
}
int test3(){
    int a,b;
    a=b=100;
}
int main(){
    cout<<"test1:"<<test1()<<endl;
    cout<<"test2:"<<test2()<<endl;
    cout<<"test3:"<<test3()<<endl;
}

打印结果:

test1:376741376
test2:376741376
test3:100

可见,只有a=b赋值后才能正确传回我们需要的数。再次\(\rm orz\)

image

image

[完结撒花]

标签:shanzr,查集,int,myFind,10010,20220724,fa,include
来源: https://www.cnblogs.com/shanzr/p/16513754.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有