题目:
计算无向图的连通分支数。
输入格式:
第一行是一个整数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;
}