实现并查集和DFS的一些有趣方法

本文探讨了并查集的简洁实现方法,强调了`leader[]`数组和`link()`函数在连接不同组时的作用。接着,文章讨论了DFS的灵活应用,包括在多参数情况下的使用,以及如何结合记忆化策略来优化问题解决。通过实例和问题解答,揭示了DFS不限于模板思维,鼓励读者成为DFS高手。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、实现并查集的简洁写法

大佬的有趣解释

int lead(int x)//
{
    if(leader[x]==x) return x;
    else return leader[x]=lead(leader[x]); //把路径上所有点都纠正
}
int link(int x,int y)
{
   if(leader[x]!=leader[y])
   {
        leader[lead(x)]=lead(y);
   }
}

leader[]表示直属上级
link()实现了两个互不相关组的连接,把x的root一起并入y的子结点中
note:return leader[x]=lead(leader[x])要用递归的思想去理解,先改变上级与root的link再递归回来改变自己。

二、关于一些DFS和DP的使用

Despite the fact that DFS has certain templates,we should not let them limit our thoughts,because we create DFS,(it is easy now to find people using DFS but it gets much harder to find a skilled DFS master.)Below are some examples.(haha,just a English Beginner trying to write something)

question1:

戳我跳转
对于dfs,经常使用递归方式实现,正向有时候很好用

从上往下依次推出金字塔各个位置上的最大值,最后比较

#include<cstdio>
int n,a[1002],i,j,ans,p;
int max(int &x,int &y){return x>y?x:y;}
int main(){
    scanf("%d",&n);
        for(i=n;i;i--)
                for(j=i;j<=n;j++)
                        scanf("%d",&p),a[j]=max(a[j],a[j+1])+p;
        for(i=1;i<=n;i++)
        ans=max(ans,a[i]);
        printf("%d",ans);
        return 0;
}

question2:关于多参数DFS的使用

戳我跳转
DFS在于实现层层递归,因此需要把重要参数层层传递。
下面这道题在进行层层深入时使用了
stp:走的步数 (用于还原路径)
sum:挖矿总数
x:要走的位置

#include<iostream>
#include<cstdio>
using namespace std;
bool v[30];//是否访问过
int bomb[30];//地雷数目
int path[30],ans[30],cnt;//path记录路径
int ac[30][30];//查看是否有通路
int n;
int maxx;//记录最大地雷数目
bool check(int x)
{
    for(int i=1;i<=n;i++){
        if(ac[x][i]&&!v[i]) return false;
    }
}
int dfs(int x,int stp,int sum)//走步数
{
    if(check(x))
    {
        if(maxx<sum)
        {
            maxx=sum;
            cnt=stp;
            for(int i=1;i<=stp;i++){
                ans[i]=path[i];
            }
        }
    }
    for(int i=1;i<=n;i++){
        if(ac[x][i]&&!v[i]){
            v[i]=1;//标记走过
            path[stp+1]=i;//记录路径
            dfs(i,stp+1,sum+bomb[i]);
            v[i]=0;
        }
    }
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++) cin>>bomb[i];
    for(int i=1;i<n;i++)
        for(int j=i+1;j<=n;j++) 
            cin>>ac[i][j];
    for(int i=1;i<=n;i++){
        v[i]=1;
        path[1]=i;
        dfs(i,1,bomb[i]);
        v[i]=0;
    }
    for(int i=1;i<=n;i++){
        v[i]=1;
        path[1]=i;
        dfs(i,1,bomb[i]);
        v[i]=0;
    }
    for(int i=1;i<=cnt;i++)
    cout<<ans[i]<<' ';
    cout<<endl<<maxx;
    return 0;
}

question3:记忆化方法实现

戳我

#include<iostream>
using namespace std;
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
int n,m,a[201][201],s[201][201],ans;
bool use[201][201];
int dfs(int x,int y)
{
    if(s[x][y]) return s[x][y];
    s[x][y]=1;
    for(int i=0;i<4;i++){
        int xx=dx[i]+x;
        int yy=dy[i]+y;
        if(xx>0&&yy>0&&xx<=n&&yy<=m&&a[x][y]>a[xx][yy]){
            dfs(xx,yy);
            s[x][y]=max(s[x][y],s[xx][yy]+1);
        }
    }
    return s[x][y];
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            cin>>a[i][j];
    for(int i=1;i<=n;i++)
       for(int j=1;j<=m;j++)
           ans=max(ans,dfs(i,j));
    cout<<ans;
    return 0;     
}

实现了每走一条路标记一条路。有点最优子结构的dp的意思了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值