蓝桥杯--七段码--并查集

今天学到了一个新的算法:并查集
不得不说:太好用惹!!!嗷!!
所以先来复盘一下并查集的思路
我在网上找了一个很生动的解释,讲的非常好,又能听懂知识点,又能记得牢,附上原博连接:这是个链接
他是以武林为例讲的并查集,并查集的作用呢,就是看一个图里的连通分支有几个,如果是一个,就代表连通图;如果是两个,就要加一条路才可以成为连通图,以此类推。
这个算法真的可以解决好多问题,好厉害的!!!
好的,不多说了,看下七段码这道题:这道题目呢,就是要把所有的连成一片的灯的情况数找出来,一个灯亮,它自己就算一片,几个灯亮,就要求这几个灯可以连起来成一片。
图论的问题,听着就复杂,但是有了并查集,喔,it’s ok~
首先呢,每个灯都是自己的祖先(自成一派),如果两个灯之间有路,代表挨着,可连通,同时它俩又都亮着,这就是一片,那么它俩就可以成一家人了,随便选一个做祖先(当家的),我们把所有亮着且连通着的灯都遍历一遍,把可以放一家的都放一家,结束后再看整张图里自己是自己的掌门人的灯有几个,就代表有几个连通分量,如果是1,就代表连成了一大片(当前某几盏灯亮的情况下)
这个呢,就又用到了dfs,这里我觉得好难想,我画栈画了好几遍,才想明白这个深度遍历是怎么回事(小辣鸡):大概是这个样子的嗷
从dfs(1)开始进入,一个一个灯的点亮,压栈,直到亮完7盏灯,然后开始看这时候的门派问题(能不能连成一片),然后出栈一个,把7灭了灯,又压栈来看门派,再出栈,这时候7的那个栈就完了,到了6是顶,执行完,灭了6,又进去点7,重复上述,等6完了,5到顶,执行完,灭了5,再进去点亮6,7,循环执行。巴拉巴拉。。。(好吧,我可能还是不会讲题给别人听)
大概的过程就是这样了,然后还有一个找祖先的函数,(因为不是一个祖先,但是又联通的是要合成一家的),也是个递归,一直找祖先是他自己的时候跳出,否则再找祖先的祖先。。。
好的,就这样吧,我觉得我明白了,嗯,结束!
喔,忘了代码,它来了

#include <bits/stdc++.h>

using namespace std;
//bool yueshu(int a,int b);
int ans=0;
int a[8][8];//连通性
int use[8];//是否开灯
int father[8];
int find_father(int n)
{
    if(father[n]==n)
        return n;
    father[n]=find_father(father[n]);
}
void dfs(int n)
{
    if(n>7)
    {
        for(int i=1;i<=7;i++)
            father[i]=i;//祖先都是自己,自成一派
        for(int i=1;i<=7;i++)
        {
            for(int j=1;j<=7;j++)
            {
                if(a[i][j]==1&&use[i]==1&&use[j]==1)
                {
                    int fa_i=find_father(i);
                    int fa_j=find_father(j);
                    if(fa_i!=fa_j)
                        father[fa_i]=fa_j;
                }
            }
        }
        int k=0;
        for(int i=1;i<=7;i++)
        {
            if(father[i]==i&&use[i]==1)
                k++;
        }
        if(k==1)
            ans++;
        return;
    }
    use[n]=1;
    dfs(n+1);
    use[n]=0;
    dfs(n+1);

}
int main()
{
    memset(use,0,sizeof(use));
    memset(a,0,sizeof(a));
    a[1][2]=a[1][6]=1;
    a[2][1]=a[2][7]=a[2][3]=1;
    a[3][7]=a[3][4]=a[3][2]=1;
    a[4][3]=a[4][5]=1;
    a[5][7]=a[5][4]=a[6][5]=1;
    a[6][1]=a[6][7]=a[5][6]=1;
    a[7][2]=a[7][3]=a[7][5]=a[7][6]=1;
    dfs(1);
    cout<<ans<<endl;
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值