• 关于集合的思路


    Description

    输入一个无向图G,计算G的连通分支数。

    Input

    有多个无向图数据。每个无向描述的第1行是两个整数n和e,分别表示顶点数和边数。接着有e行,每行有2个整数a、b,分别是一条边的两个端点(起点和终点)。两个图之间空一行。

    Output

    对每个无向图,输出图中连通分支个数。

    Sample Input

    2 1 1 2 5 8 1 2 1 3 1 4 1 5 2 3 2 4 3 4 4 5

    Sample Output

    1 1
    先看这个,嗯,说白了就是集合起来神马的,我百度了一下,草,是BFS耶
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define maxlen 1100
    using namespace std;
    bool maps[maxlen][maxlen];
    int visited[maxlen];
    int n,m;
    void dfs(int i)
    {
        if(visited[i])
            return ;
         visited[i]=true;
         for(int j=1;j<=n;++j)
         {
             if(maps[i][j]==true&&!visited[j])
             {
                 dfs(j);
             }
        }
     }
     int main ()
    {
         int a,b;
         while(scanf("%d%d",&n,&m)!=EOF)
         {
             for(int i=0;i<=n;++i)
             for(int j=0;j<=n;++j)
             {
                 if(i==j)
                     maps[i][j]=1;
                 else
                    maps[i][j]=0;
            }
             for(int i=0;i<m;++i)
            {
                 scanf("%d%d",&a,&b);
                 maps[a][b]=maps[b][a]=true;
             }
             memset(visited,0,sizeof(visited));
             int ans=0;
             for(int i=1;i<=n;++i)
             {
                 if(!visited[i])
                 {
                     dfs(i);
                     ans++;
                 }
             }
           printf("%d
    ",ans);
         }
     }
    

      然后再看下一道

    Description

    超级无敌张小豪是A国的一名勇士,A国的勇士都要靠获得能量变得更强,在A国勇士获得能量只有唯一的一种途径就是膜拜宙斯神——周尼玛(桑!!!)。要膜拜周尼玛就要去到遥远的大日国那里有好多好多周尼玛(桑!!!)。但是周尼玛(桑!!!)是一种群居动物,一队周尼玛(桑!!!)中都有且只有一个领袖叫周尼玛你妹(桑!!!)超级无敌张小豪勇士必须拿着一炷香到周尼玛你妹(桑!!!)面前膜拜三下即可获得一点能量。

    膜拜必须遵循一些规则:

    对于一个周尼玛你妹(桑!!!)只能膜拜一次;

    不能膜拜周尼玛(桑!!!);

    一次膜拜用一炷香且一炷香只能膜拜一次;

    现在问题出现了,小豪准备启程去大日国,在走之前小豪要准备买香但是小豪不知道大日国一共有几队周尼玛(桑!!!),小豪既想每个周尼玛你妹(桑!!!)都膜拜到,又想带过去的香能用完不浪费。于是小豪打听小道消息搞过来了一张周尼玛(桑!!!)家族谱。

    家族谱上有若干对数字

    eg:1 2

        2 4

    表示:周尼玛1号和周尼玛2号是一队的

          周尼玛2号和周尼玛4号是一队的

    若谱上告诉你周尼玛x号和周尼玛y号是一队的周尼玛y号和周尼玛z号是一队的

    那也就代表了周尼玛x号和周尼玛z号是一队的了。

    Input

    The input starts with an integer T(1<=T<=10) which indicate the number of test cases. Then T test cases follow. Each test case starts with two integers N and M(1<=N<= 30000,1<=M<= 500000). N indicates the number of周尼玛, the 周尼玛 are marked from 1 to N. Then M lines follow. Each line consists of two integers A and B(A!=B), that means 周尼玛 A号 and 周尼玛 B号 in the same team. There will be a blank line between two cases.

    Output

    For each test case, just output how many tables Ignatius needs at least. Do NOT print any blanks. 

    Sample Input

    2 5 3 1 2 2 3 4 5 5 1 2 5

    Sample Output

    2 4
    先让我说一句,周尼玛尼玛个大鬼头!!!我都被尼玛洗脑有木有?!
    嗯,感觉和上面一样.....还是用BFS,但是看看1<=N<= 30000,1<=M<= 500000.....一股不祥的预感.....果然超时了.....
    看了一下网上解法,原来是并查集.....
    #include <iostream>
    using namespace std;
    
    const int N=30000;
    int flag[N];
    
    int Find_Set(int x)
    {
        if(x!=flag[x])
        {
            flag[x]=Find_Set(flag[x]);
        }
        return flag[x];
    }
    
    int main()
    {
        int t,m,n,i,j,a,b,A,B,num;
        cin>>t;
        while(t--)
        {
            cin>>n>>m;
            for(i=1;i<=n;i++) flag[i]=i;
            num=n;
            for(i=1;i<=m;i++)
            {
                cin>>A>>B;
                a=Find_Set(A);
                b=Find_Set(B);
                if(a>b)
                {
                    flag[a]=b;
                    num--;
                }
                else if(a<b)
                {
                    flag[b]=a;
                    num--;
                }
            }
            cout<<num<<endl;
        }
        return 0;
    }
    

      然后再倒过来再考虑一下能否用并查集搞定无向图的连通支路?

    #include <iostream>
    #include <string.h>
    using namespace std;
    
    const int N=30000;
    int flag[N];
    
    int Find_Set(int x)
    {
        if(x!=flag[x])
        {
            flag[x]=Find_Set(flag[x]);
        }
        return flag[x];
    }
    
    int main()
    {
        int t,m,n,i,j,a,b,A,B,num;
        while(scanf("%d%d",&n,&m)!=EOF)
        {
        	memset(flag,0,sizeof(flag)); 
        	for(i=1;i<=n;i++) flag[i]=i;
            num=n;
            for(i=1;i<=m;i++)
            {
                cin>>A>>B;
                a=Find_Set(A);
                b=Find_Set(B);
                if(a>b)
                {
                    flag[a]=b;
                    num--;
                }
                else if(a<b)
                {
                    flag[b]=a;
                    num--;
                }
            }
            cout<<num<<endl;
        
    	}
    	return 0;
    }
    

      就这样搞定了.....突然觉得我真不是搞ACM的材料.....妈蛋

  • 相关阅读:
    final 和 abstract 抽象类
    ajax的同步 和 异步
    自定义控件进阶01_侧滑菜单_快速索引
    自定义控件基础02_下拉刷新_侧拉菜单_自定义属性
    自定义控件基础01_菜单轮__viewPager_下拉框_自定义开关
    解决xxview.measure(0, 0)主动测量控件报错 android.view.InflateException
    Android Studio 笔记
    百度地图_api
    手机卫士13_屏幕适配_异常处理_盈利模式_混淆加密
    手机卫士12_软件锁,应用程序相关
  • 原文地址:https://www.cnblogs.com/zhko11993/p/3809160.html
Copyright © 2020-2023  润新知