图的遍历——深度优先搜索
题目描述
深度优先搜索遍历类似于树的先根遍历,是树的先根遍历的推广。其过程为:假设初始状态是图中所有顶点未曾被访问,则深度优先搜索可以从图中的某个顶点v出发,访问此顶点,然后依次从v的未被访问的邻接点出发深度优先遍历图,直至图中所有和v有路径相通的顶点都被访问到;若此时图中尚有顶点未被访问,则另选图中一个未曾被访问的顶点作为起始点,重复上述过程,直至图中所有顶点都被访问到为止。
在本题中,读入一个无向图的邻接矩阵(即数组表示),建立无向图并按照以上描述中的算法遍历所有顶点,输出遍历顶点的顺序。
输入描述
输入的第一行包含一个正整数n,表示图中共有n个顶点。其中n不超过50。
以后的n行中每行有n个用空格隔开的整数0或1,对于第i行的第j个0或1,1表示第i个顶点和第j个顶点有直接连接,0表示没有直接连接。当i和j相等的时候,保证对应的整数为0。
输入保证邻接矩阵为对称矩阵,即输入的图一定是无向图。
输出描述
只有一行,包含n个整数,表示按照题目描述中的深度优先遍历算法遍历整个图的访问顶点顺序。每个整数后输出一个空格,并请注意行尾输出换行。
样例
输入
4
0 1 0 1
1 0 0 0
0 0 0 1
1 0 1 0
输出
0 1 3 2
一些题外话(没啥用,不看也没事)
在本题中,需要熟练掌握图的邻接矩阵存储方式。在建立完成无向图之后,需要严格按照题目描述的遍历顺序对图进行遍历。另外,算法中描述的FirstAdjVex函数和NextAdjVex函数,需要认真的自行探索并完成。
通过这道题目,应该能够对图的深度优先搜索建立更加直观和清晰的概念。
理思路
关于深度优先搜索的过程,题目描述写的就很详细了,自行研读即可
所以我们只理一下关键代码该怎么写
函数部分
深搜这一类题,因为它本身就是通过递归实现,所以我们会单独写一个深搜的函数
d
f
s
dfs
dfs,在函数中写完深搜的主要操作,再在主函数中实现输入输出调用函数等操作
首先,在图的邻接矩阵中,假如一点有连线,那么相应的在邻接矩阵中对应的
a
[
x
]
[
y
]
a[x][y]
a[x][y]也会相应的有值(一般是赋成1,有边权就赋成边权)
所以依照这一思路,似乎我们只要按照先依次遍历
a
[
0
]
[
i
]
a[0][i]
a[0][i]找到值,在从找到的值对应的i所对应的行,继续遍历即可
但是注意俩字 似乎
由于图可能并非连通图,所以从点1开始找可能无法一下子遍历到所有顶点。
所以这是就要引出另一个重要元素 访问数组
这个数组就是用来保存哪些点被遍历了,哪些点没有,第一遍遍历完后其余点自然就代表还会有若干个连通块。
所以,我们在处理中,通过遍历访问数组
v
i
s
i
t
e
d
visited
visited,就能达到遍历每一个点的作用
最后,只要在函数内对行的遍历中,加上一个
… && !visited[i]
来判断当前对应点是否已被遍历过,就可以了
AC代码
#include<iostream>
#include<cstdio>
using namespace std;
int a[60][60];
int n; //把n定义成全局变量,函数调用方便些
//灰常灰常重要的深搜函数
int visited[60];
void dfs(int t) {
visited[t] = 1; //表示当前点已被遍历
printf("%d ", t); //题目要求的输出
//遍历邻接矩阵中该顶点对应的行
for(int i = 0; i < n; i++){
if (a[t][i] && !visited[i]) {
dfs(i); //递归调用
}
}
}
int main(){
//平平无奇的输入
scanf("%d", &n);
for(int i = 0; i < n; i++){
for(int j = 0; j < n; j++){
scanf("%d", &a[i][j]);
}
}
//遍历访问数组
for(int i = 0; i < n; i++){
if (visited[i] == 0){
dfs(i);
}
}
return 0;
}