深度优先索索和递归有所联系,我们所知道的递归求阶乘和斐波那契都可以称作深度优先搜索。
1.首先来了解一下基本的递归——斐波那契数列。当 n = 10时,cnt = 109.
#include <iostream>
using namespace std;
int cnt = 0;
int fib(int n)
{
cnt++;
if (n == 1 || n == 2) {
return 1;
}
return fib(n - 1) + fib(n - 2);
}
//int main()
//{
// int n;
// cin >> n;
// cout << "fib(n) = " << fib(n) << endl;
// cout << "cnt = " << cnt << endl;
// return 0;
//}
这种复杂度高达2的n次方。可以用data[25]来记录已经求过的fib(n)来进行优化。
当n = 10时,cnt = 17,相比之前的109次可以大大减少。
#include <iostream>
using namespace std;
int cnt = 0;
int data[25];
int fib(int n)
{
cnt++;
if (n == 1 || n == 2) {
return 1;
}
if (data[n] != 0) {
return data[n];
}
data[n] = fib(n - 1) + fib(n - 2);
return data[n];
}
int main()
{
int n;
cin >> n;
cout << "fib(n) = " << fib(n) << endl;
cout << "cnt = " << cnt << endl;
return 0;
}
2.用dfs递归求全排序
#include <iostream>
using namespace std;
int a[10] = { 1,2,3,4,5,6,7,8,9,10 };
int b[10];
bool vis[10];
bool dfs(int s, int t) {
if (s == t) {
for (int i = 0; i < t; i++) {
cout << b[i] << " ";
}
cout << endl;
return true;
}
for (int i = 0; i < t; i++) {
if (!vis[i]) {
vis[i] = 1;
b[s] = a[i];
dfs(s + 1, t);
vis[i] = 0;
}
}
}
int main()
{
int n;
cin >> n;
dfs(0, n); //前n个数的全排列
return 0;
}
3.若为迷宫搜索,则向上下左右四个方向搜索,则代码为:
bool dfs(int x,int y)
{
if ((x,y)是终点 ){
//找到了路径,也就是递归结束的标志
return true;
}
标记(x,y)已经访问
向上走到位置(tx, ty)
if (x,y)在地图里且未被访问 {
if (dfs(tx, ty) == true){
return true;
}
}
向下走到位置(tx, ty)
if (x,y)在地图里且未被访问 {
if (dfs(tx, ty) == true){
return true;
}
}
向左走到位置(tx, ty)
if (x,y)在地图里且未被访问 {
if (dfs(tx, ty) == true){
return true;
}
}
向右走到位置(tx, ty)
if (x,y)在地图里且未被访问 {
if (dfs(tx, ty) == true){
return true;
}
}
取消(x, y)的标记
}
例题
#include <iostream>
using namespace std;
int n;
char area[50][50];//表示地图
int vis[50][50]; //标记
int dic[4][4] = {{0,1},{1,0},{0,-1},{-1,0}};
bool in(int x,int y){
return x>=0 && x<n && y>=0 && y<n;
}
bool dfs(int x,int y){
if (area[x][y] == 'T'){
return true;
}
area[x][y] = 'm'; //表示路径,路径用m表示
vis[x][y] == true;
for (int i=0; i<4; i++){
int tx = x + dic[i][0];
int ty = y + dic[i][1];
if (!vis[tx][ty] && in(tx, ty) && area[tx][ty]!='*'){
if (dfs(tx, ty)){ //注意不能写return dfs(tx, ty)
return true;
}
}
}
area[x][y] = '.'; //溯回时取消路线标记m
vis[x][y] = false;
return false;
}
int main()
{
int x, y;
cin>>n;
for (int i=0; i<n; i++){
for (int j=0; j<n; j++){
cin >> area[i][j];
}
}
for (int i=0; i<n; i++){
for (int j=0; j<n; j++){
if (area[i][j] == 'S'){
x = i;
y = j;
}
}
}
if (dfs(x,y)){
for (int i=0; i<n; i++){
for (int j=0; j<n; j++){
cout<<area[i][j];
}
cout<<endl;
}
}
else{
cout<<" NO "<<endl;
}
return 0;
}
ps.如果题目改成求最短路径的长度,那该怎么做呢?
可以用ans来存储每次达到终点时的步数,可以理解为二叉树求高度,每次递归时传递step+1
#include <iostream>
using namespace std;
int n;
int ans = INT_MAX;
char area[50][50];//表示地图
int vis[50][50]; //标记
int dic[4][4] = {{0,1},{1,0},{0,-1},{-1,0}};
bool in(int x,int y){
return x>=0 && x<n && y>=0 && y<n;
}
void dfs(int x,int y,int step){
if (area[x][y] == 'T'){
if (step<ans){
ans = step;
}
return;
}
vis[x][y] == true;
for (int i=0; i<4; i++){
int tx = x + dic[i][0];
int ty = y + dic[i][1];
if (!vis[tx][ty] && in(tx, ty) && area[tx][ty]!='*'){
dfs(tx,ty,step+1);
}
}
vis[x][y] = false;
}
int main()
{
int x, y;
cin>>n;
for (int i=0; i<n; i++){
for (int j=0; j<n; j++){
cin >> area[i][j];
}
}
for (int i=0; i<n; i++){
for (int j=0; j<n; j++){
if (area[i][j] == 'S'){
x = i;
y=j;
}
}
}
dfs(x,y,0);
return 0;
}