1. 深度优先遍历
1. 算法框架
1. 邻接表存储的搜索算法
int visited[n];//n为结点的个数
graph head[100];//graph为邻接表存储类型
dfs(int k){//head图的顶点数组
edgenode * ptr;//图的指针
visited[k] = 1;
print("访问",k);
ptr = head[k].firstedge;
while(ptr != null){//遍历至链表尾
if(visited[pre->vertex] = 0){
dfs(ptr -> vertex);//递归遍历
ptr = ptr -> nextnode;//下一个顶点
}
}
}
2. 零阶矩阵存储的搜索算法
int visited[n];//有n个顶点
int g[n][n];
dfsm(int k){
printf("访问",k);
visited[k] = 1;
for(int i = 0;i < n;i++){
if(g[k][j] = 1 && visited[j] == 0){
dfsm(j);
}
}
}
2 深度优先搜索的应用
例1:走迷宫问题
题目:
- 依然是利用例2的迷宫图,进行存储和解决该问题,详见广度优先遍历c
算法分析:
- 使用深度优先搜索,就是一直向着可同行的下一个方格走,直到搜索到出口就找到解;如果行不通则返回上一个方格(这里空想比较难理解,因为本身就在递归中,而这个题之所以可以控制返回即回溯,就是因为search中的for循环),继续搜索其他方向
- 数据结构设计:利用迷宫本身的存储空间,除了记录方格走过的信息,我们还要标识是否可行
- 实现程序
#include<stdio.h>
#define N 8
int total;
int maze[N][N] = { {0,0,0,0,0,0,0,0},
{0,1,1,1,1,0,1,0},
{0,0,0,0,1,0,1,0},
{0,1,0,0,0,0,1,0},
{0,1,0,1,1,0,1,0},
{0,1,0,0,0,0,1,1},
{0,1,0,0,1,0,0,0},
{0,1,1,1,1,1,1,0} };
int fx[4] = { -1,1,0,0 }; int fy[4] = { 0,0,-1,1 };
int check(int i, int j ,int k) {
int flag = 1;
i = i + fx[k]; j = j + fy[k];
if (i < 0 || i>7 || j < 0 || j>7) {//是否在迷宫内
flag = 0;
}
else if (maze[i][j] != 0) {//是否可行
flag = 0;
}
return flag;
}
void Out() {
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (maze[i][j] == 3) {
total++;
}
printf("%d ", maze[i][j]);
}
printf("\n");
}
printf("有%d步数\n", total);
return;
}
void search(int i,int j) {
int newi, newj;
for (int k = 0; k < 4; k++) {
if (check(i,j ,k)== 1) {
newi = i + fx[k]; newj = j + fy[k];
maze[newi][newj] = 3;
if (newi == 7 && newj == 7) {
Out();
return;
}
else {
search(newi, newj);
}
}
}
maze[i][j] = 2;//表示该点已经判断出来不可以再走了
return;
}
void main() {
total = 1;
maze[0][0] = 3;
search(0, 0);
return;
}
小结:
- 本算法和广度优先搜索算法一样,每个方格有四个方向可以遍历,这样一个结点(方格)有可能多次成为一个活结点,而在广度优先算法中,一个结点(方格)就只有一次成为活结点,出队后就变为了死结点,不再进行操作
- 与过度优先算法相比,在空间效率上二者相近,都需要赋值空间
- 用过度有限算法最先搜索到的是一条左端路径,而用深度搜索,则可以很快的找到一条可行的路劲;但是如果要通过深搜法确保找到最短路径,则需找到所有路劲,再从中筛选出最短路径
例2:七巧板涂色问题
题目:
有如题的七巧板,试设计算法,使用至多4中不同的颜色对七巧板进行涂色,要求相邻区域的颜色互不相同,打印输出所有的可能涂色的方案
![](https://i-blog.csdnimg.cn/blog_migrate/d827577b8c8e98052fba8c59cedfe3ca.png)
算法分析:
-
该例中就使用了深搜的方法
-
再深搜是并不加入任何涂色的策略,只是对每个顶点逐次尝试4种颜色
-
检查是否和其相邻结点颜色发生了冲突
-
如果没有发生冲突,则按一项方式继续进行试探;
如果发生了,返回到上一个还没有尝试完4种颜色的结点
-
-
程序实现
#include<stdio.h>
//使用零阶矩阵存储七巧板
int a[7][7] = { {0,1,0,0,1,0,1},
{1,0,0,1,0,1,0},
{0,0,0,1,0,0,1},
{0,1,1,0,0,1,1},
{1,0,0,0,0,0,1},
{0,1,0,1,0,0,0},
{1,0,1,1,1,0,0} };
int color[7] = { 0 };//激素1~7的卡盘个图什么色号
int total;//记录有几种涂色的方法
int check(int t) {
int flag = 0;
//判断相邻的卡片颜色是否冲突
for (int i = 0; i < t; i++) {
if (a[i][t] == 1 && color[i] == color[t] ) {
flag = 1;
break;
}
}
return flag;
}
void Out() {
printf("*********第%d个解决方案******\n",total+1);
total++;
for (int i = 0; i < 7; i++) {
printf("第%d的颜色是%d\n", i + 1, color[i]);
//color[i] = 0;//初始化color数组,便与下一次的搜索
}
return;
}
void try(int t) {
if (t == 7) {
//表示7个卡片已经填充完毕
Out();
}
else {
for (int k = 1; k <= 4; k++) {//用1~4代表不同的颜色
color[t] = k;
if (check(t)==0) {//如果颜色填充不冲突
try(t + 1);
}
}
}
return;
}
void main() {
total = 0;
try(0);//有1好开始填充颜色==枚举
printf("total = %d", total);
return;
}