用DFS解决迷宫最短路径问题的一些思考
Some Words
摆烂了两天,才开始思考DFS究竟该怎么写出来。也是遇到了很多的问题。
比如如何表示方向呢,如何输出没有通路的条件……
现在也是写出来了,果不其然差一点超时。
毕竟DFS是找出所有通路后比较最小值的递归嘛
所以为什么还要学DFS
About Problem
直接去看上一篇post喵~
Thinking Process about this problem
DFS若是寻找最优解的化必不可少的便是循环或者递归。
循环不知道要穷举多少例子,而递归似乎是个不错的方法。
通过step计数,在起点的时候为1,每走到一层便step加1,使其中遇到的第一个节点成为新的起点递归,直到终点停止。通过for循环转变方向继续递归,若是能到终点便比较step与min。最后记录下来最短路径
若是没有通路,则记录最短路径的容器为空(以此便可作为条件了)。
好了,看文字基本没什么用,还是分析代码有意思(●ˇ∀ˇ●)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include<stdio.h>
#include<cstring>
using namespace std;
int m, n, Min = 98769954;
int a[1005][1005];
int vis[1005][1005];
typedef struct point
{
int x3, y3, d3;
} Point;
Point path[100010];
Point shortest_path[10010];
int moves[4][2] = { {0,1},{1,0 },{0,-1},{-1,0} };
void dfs(int x, int y, int step)
{
if (x == m && y == n)
{
if (step < Min)
{
Min = step;
for (int i = 0;i < step;i++)
{
shortest_path[i] = path[i];
}
}
return;
}
for (int i = 0; i < 4; i++)
{
int nx = x + moves[i][0];
int ny = y + moves[i][1];
if (nx<1 || nx>m || ny<1 || ny>n) continue;
if (vis[nx][ny] == 0 && a[nx][ny] == 1)
{
vis[nx][ny] = 1;
path[step].x3 = nx;
path[step].y3 = ny;
path[step].d3 = i+1;
dfs(nx, ny, step + 1);
vis[nx][ny] = 0;
}
}
return;
}
int main()
{
while (scanf("%d%d", &m, &n))
{
if (m == 0 && n == 0) {
return 0;
}
for (int i = 1; i <= m; i++)
for (int j = 1; j <= n; j++)
{
scanf("%d", &a[i][j]);
}
vis[1][1] = 1;
path[0] = { 1,1 };
dfs(1, 1, 1);
int count = 0;
if (shortest_path[0].x3 == 0 && shortest_path[0].y3 == 0)
{
cout << "没有通路" << endl;
}
else
{
for (int i = 0;i <= Min - 1;i++)
{
if (i != Min - 1) {
printf("(%d,%d,%d)", shortest_path[i].x3, shortest_path[i].y3, shortest_path[i + 1].d3);
count++;
}
if (count == 5)
{
cout << endl;
count = 0;
}
else if (i == Min - 1)
{
printf("(%d,%d,%d)", shortest_path[i].x3, shortest_path[i].y3, 0);
cout << endl;
}
}
}
memset(shortest_path,'\0',sizeof(shortest_path));
memset(path, '\0', sizeof(path));
memset(vis, '\0', sizeof(vis));
Min = 98769954;
}
}
Final
哎呀,又花了很多时间理解,这种找路径的问题再加上递归简直是折磨人。递归还是一如既往的折磨人啊,很难理解。
其实若是类比为数学归纳法的话便好理解一些了。
首先写出Base case。在递归中便是递归最基本的情况。有时是起点,而有时候又会是重点,但不变的是,它一定是约束函数中变量的条件。
其次便开始思考n或者n+1的情况,n如何到n+1,甚至于起点如何到终点。这之间过程的模拟需要不断利用该函数进行模拟(好像链表一样)
(很烂的比喻)
本文由作者按照
CC BY 4.0
进行授权