深搜(看这一篇就够了)

本文详细介绍了深度优先搜索算法,包括其基本概念、应用示例(如全排列问题、迷宫问题中的路径探索),以及在数塔问题中的优化策略。着重讨论了回溯法在解决问题过程中的关键作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

深搜简介

深搜是一种对数串或图形进行遍历的算法。它会从起点像树状图一样向下进行探索,如果发现不能到达目标解,那就返回到上一个节点,然后从另一条路开始走到底 ,这种尽量往深处走的概念即是深度优先的概念。回溯是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。

深度优先搜索是对图进行搜索的算法,目的也都是从起点开始搜 索直到到达指定顶点(终点)。深度优先搜索会沿着一条路径不断往下搜索直到不能再继续为止,然后再折返,开始搜索下一条候补路径。

深搜大概可以分为两种

全排列问题

一种需要将规定条件下的所有情况输出的问题

就是填空,要输出的东西是一个个空,每次用循环来枚举填的空的范围,找到符和要求的数,从而填空。填完一个空又去填下一个空。

经典例题

题目描述

输出自然数1~n所有不重复的排列,即n的全排列,要求所产生的任一数字序列中不允许出现重复数字。

输入

1<=n<=9

输出

由1~n组成的所有不重复的数字序列。每行一个序列

样例输入 

3

样例输出 

1 2 3

1 3 2

2 1 3

2 3 1

3 1 2

3 2 1

代码
#include <bits/stdc++.h>
using namespace std;
bool a[11];
int b[11];
int n;
void out()
{
	for(int i=1;i<=n;i++)
	{
		cout<<b[i]<<" ";
	}
	cout<<endl;
} 
void dfs(int i)
{
	for(int j=1;j<=n;j++)//枚举填的范围
	{
		if(a[j]==0)
		{
			b[i]=j;
			a[j]=1;
			if(i==n)//填完了
			{
				out();//输出
			}
			else
			{
				dfs(i+1);
			}
			a[j]=0;//回溯(重点⭐⭐⭐)
		}
	}
}
int main()
{
	cin>>n;
	dfs(1);//该填的位数
	return 0;
}

迷宫类问题 

题目描述

给定一个迷宫和其中的障碍(可有可无),在迷宫内按规定走法四处乱走。如果走不通,则需要返回,进行恢复现场,直到走到终点。最经典的莫过于走迷宫问题(有障碍):

   给定一个N*M方格的迷宫,迷宫里有T处障碍,障碍处不可通过。给定起点坐标和终点坐标,问: 每个方格最多经过1次,有多少种从起点坐标到终点坐标的方案。在迷宫中移动有上下左右四种方式,每次只能移动一个方格。数据保证起点上没有障碍。

输入

    第一行N、M和T,N为行,M为列,T为障碍总数。第二行起点坐标SX,SY,终点坐标FX,FY。接下来T行,每行为障碍点的坐标。

输出

    给定起点坐标和终点坐标,问每个方格最多经过1次,从起点坐标到终点坐标的方案总数。

样例输入

2 2 1

1 1 2 2

1 2

样例输出

1

提示

【数据规模】

  1≤N,M≤5

代码
#include <bits/stdc++.h>
using namespace std;
bool a[7][7],l[7][7];
int x,xx,y,yy,za,zi;//N、M和T,N为行,M为列,T为障碍总数。起点坐标:x,xx  终点坐标y,yy。za,zi是障碍物的坐标。
int n,m,t,ans;
void s(int w,int q)
{
	if(w>n||q>m||w<1||q<1||a[w][q]==1||l[w][q]==1)//如果出界或起始点不在界内或在障碍物上或走到之前走过的地方 
	{
		return;//返回上一位 
	}
	if(w==y&&q==yy)//到了终点 
	{
		ans++;
		return;
	}
	l[w][q]=1;//将之前走过的地方标记 
	s(w+1,q);//向四周走 
	s(w-1,q);
	s(w,q+1);
	s(w,q-1);
	l[w][q]=0;//回溯(重点⭐⭐⭐)
	return;
}
int main()
{
	cin>>n>>m>>t>>x>>xx>>y>>yy;
	for(int i=1;i<=t;i++)
	{
		cin>>za>>zi;
		a[za][zi]=1;//标记
	}
	s(x,xx);
	cout<<ans;
	return 0;
}

 

特殊迷宫类问题:

数塔问题

题目描述

      有形状如图所示的数塔,从顶部出发,在每一结点可以选择向左走或是向右走,一起走到底层,要求找出一条路径,使路径上的值的和最大。

5

7

3 8

8 1 0

2 7 4 4

4 5 2 6 5

输入

第一行是一个整数N(1 <= N <= 100),表示数塔的高度,接下来用N行数字表示数塔,其中第i行有个i个整数,且所有的整数均在区间[0,99]内。

输出

输出可能得到的最大和

样例输入

5

7

3 8

8 1 0

2 7 4 4

4 5 2 6 5

样例输出

max=30

提示

用二维数组存储的时候不需要管空格,如样例那样存储就可以了。

代码
#include <bits/stdc++.h>
using namespace std;
int n,maxx,ans;
int t[110][110];
void s(int x,int y,int k)
{
	k=k+t[x][y];//加上走过的路上的数 
	if(x==n)
	{
		if(maxx<k)
		{
			maxx=k;
		}
		return;
	}
	s(x+1,y,k);
	s(x+1,y+1,k);
	k=k-t[x][y];//回溯(重点⭐⭐⭐)
	return; 
}
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=i;j++)//每行都比上一行多一格 
		{
			cin>>t[i][j];
		}
	}
	s(1,1,0);	
	cout<<"max="<<maxx;
	return 0; 
}

数塔问题还可以用上广搜与动态规划,我以后再讲!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值