离散数学 习题篇 —— 图的基本概念——连通分支数

题目:

计算无向图的连通分支数。

输入格式:

第一行是一个整数V,表示图有V个结点,结点编号0,1,2,…,V−1(1≤V≤10,000)

第二行是一个整数E,表示图中有E条边。(0≤E≤100,000)

接下来有E行,每行表示一条边,用空格分隔的两个整数表示边的两个端点。

输出格式:

一个整数,表示其连通分支数。

输入样例:

13
13
0 5
4 3
0 1
9 12
6 4
5 4
0 2
11 12
9 10
0 6
7 8
9 11
5 3

输出样例:

3

题解:

判断有多少个连通分支。就每个点都试一下,看看走过了没有。没走过就进去逛一圈,走过了就算了。画个图看看吧:
在这里插入图片描述
这个图有两个连通分支,分别是{1,2,3,4,5,6}和{7,8,9,10}。
用刚刚的思路的话,就是先从1进去试试,发现1没去过,就走一圈能够走到2,3,4,5,6。那就标记这些点都走过了,在从2进去试试,发现2用过了,不走了。就这样一直到了7,发现没走过,就进去试试,于是走过了7,8,9,10这几点,再往后试能不能进去,发现都用过了。进去了两次,也就是有两个连通分支。
这个图有点特殊嗷,可以说都是一条线的,那再来个复杂的试试:
在这里插入图片描述
这个图是一个K5一个K4组成的,两个连通分量{1,2,3,4,5}和{6,7,8,9}
这样的话,我们来看一下,怎么个玩法:

首先来1号看看,发现1号没走过,就进去看看,发现可以去到2,3,4,5几个点嗷,那先去2号点看看吧。走到2号点,发现可以去1,3,4,5几个点,去哪个呢,去1号看看?哦~1号看过了,那就去下一个,3号吧。噔噔噔,跑到了3号点。三号能去哪呢?1,2,4,5。再按顺序去看看吧。去1看看,去过了。去2看看,也去过了,就去4吧。。。就这样一路到了5。从5去那呢?1,2,3,4都去过了,也没有别的点了,哎,逛完了呀,回去吧!原路返回溜了溜了,从哪来的?4号。到了4号接着返回,3,2,1。哦,逛完了,还有没有别的能逛的?

刚刚是不是从1号进去试试了,那么这次从2号进去试试。注意嗷,上次去2号是进去以后到的,这次是直接把2号当作入口。发现2号去过了,玩过了就不玩了,下一个!

就这样,找到了6号点。

哎,一个新点啊,去看看去看看。于是从6号进去以后又像是1号一样逛了一圈,逛了7,8,9三个点。出来又试了试7,8,9几个入口,发现都不能进。点都遍历完了就遍历完成了。

那么一共进去了两次,就是两个连通分支呗。

如果还懂就多看几遍吧,看懂了就上代码了(从主函数先看嗷)

代码:

#include <bits/stdc++.h>
using namespace std;
//n个点和m个边
int n, m;
//邻接表存图:G[i]表示i这个点能去的点,比如刚刚的K5和K4的那个图,G[1]={2,3,4,5}
vector<vector<int> > G;
//判断点访问过了没有
vector<bool> color;

//“进去看看”
void dfs(int k)
{
	//如果进来以后发现这个点访问过了,就回去咯
    if(color[k] == true)
        return ;
    //进来以后发现没来过,那就玩一圈。并且设置为来过了。
    color[k] = true;
    //去这个点能去的每个点看看。
    for(int i : G[k])
        dfs(i);
}

//从这里先看是个好习惯
int main(int argc, char const *argv[])
{
	//输入点数和边数
    cin >> n >> m;
	//初始化一下先
    G.resize(n);
    color.resize(n);
    fill(color.begin(), color.end(), false);
    //输入边
    while (m--)
    {
        int a, b;
        cin >> a >> b;
        //表示a可以去b
        G[a].push_back(b);
        //表示b可以去a
        G[b].push_back(a);
    }
    int cnt = 0;
    //每个点都当“入口”试试
    for(int i = 0; i < n; ++i)
    {
    	//如果这个点没有访问过就进去看看
        if(color[i] == false)
        {
        	//能进来的话就是一个新的分支了
            cnt++;
            dfs(i);
        }
    }
    cout << cnt;
    return 0;
}
  • 12
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值