题目要求:
给定一个有n个顶点和m条边的无向图,请用深度优先遍历(DFS)和广度优先遍历(BFS)分别列出其所有的连通集。假设顶点从 0 到n-1编号。进行搜索时,假设我们总是从编号最小的顶点出发,按编号递增的顺序访问邻接点。
输入格式:
输入第 1 行给出 2 个整数 n(0<n<=10) 和m,分别是图的顶点数和边数。随后m行,每行给出一条边的两个端点。每行中的数字之间用 1 空格分隔。
输出格式:
按照"{ v1 v2 ... vk }"的格式,每行输出一个连通集。先输出 DFS 的结果,再输出 BFS 的结果。
输入样例 :
8 6
0 7
0 1
2 0
4 1
2 4
3 5
输出样例:
{ 0 1 4 2 7 }
{ 3 5 }
{ 6 }
{ 0 1 2 7 4 }
{ 3 5 }
{ 6 }
题解:
思路如注释所示,可通过所有测试点。
#include<bits/stdc++.h>
using namespace std;
const int MAX_N = 10;
vector<int> adj[MAX_N];
bool visited[MAX_N]; //记录元素是否被访问过
void DFS(int v,vector<int> &component){
visited[v] = true;
component.push_back(v);
//按编号递增的顺序访问邻接结点
sort(adj[v].begin(),adj[v].end());
for(int u : adj[v]){ //把v的邻接点遍历完
if(!visited[u]){
DFS(u,component); //递归
}
}
}
void BFS(int v,vector<int> &component){
queue<int> q; //用队列辅助进行广度优先搜索
q.push(v);
visited[v] = true;
while(!q.empty()){
int u = q.front();
q.pop();
component.push_back(u);
//按编号递增的顺序访问邻接点
sort(adj[u].begin(),adj[u].end());
for(int w:adj[u]){
if(!visited[w]){
q.push(w);
visited[w] = true;
}
}
}
}
int main(){
int n,m;
cin>>n>>m;
for(int i =0; i < m; i++){
int u,v;
cin>>u>>v;
adj[u].push_back(v);
adj[v].push_back(u);
}
//DFS找连通分量
fill(visited, visited+n, false); //清空visited上的标记
for(int i = 0; i < n; i++){
if(!visited[i]){
vector<int> component; //设定一个component变量用来存储一个连通集的所有元素
DFS(i,component);
cout<<"{ ";
for(int v:component){
cout<<v<<" ";
}
cout<<"}"<<"\n";
}
}
//BFS找连通分量
fill(visited,visited+n,false);
for(int i = 0;i < n; i++){
if(!visited[i]){
vector<int> component;
BFS(i,component);
cout<<"{ ";
for(int v:component){
cout<<v<<" ";
}
cout<<"}"<<"\n";
}
}
return 0;
}
总结:
这题用到了很多stl函数,我也是刚学它们的性质,所以这道题很有参考价值。
1.vector<int> 型数组对此题使用很方便可以直观的存储每个结点的邻接表,而且可以动态的改变大小,太牛了。
2.fill函数可以直接把数组的给定下标范围统一修改成一个设定值,这题里用来初始化visited[]数组。
3.sort函数默认从小到大排序,在存储每一个连通集时可以保证题目中所要求的连通性。
4.“for(int v:component) ”表达式,这是一个输出容器中元素的简洁方法。把每个元素的值赋值给v进行操作。
5.注意输出格式,每个元素中间隔有space。
一下包含了stl的这么多函数,这题我要重点复习^_^