深搜dfs广搜bfs

dfs模板:

dfs可以理解成通过递归运算,计算机每次从一个分支走到底,然后通过回溯找下一个可行的路径

void dfs(int num,......)//参数用来表示状态  
{  
    if(判断边界)  
    {  
        ...//根据题意添加  
        return;  
    }  
    if(越界或者是不合法状态)  
        return;  
    for(扩展方式)  //也可能是if根据题意使用适合的方式
    {  
        if(扩展方式所达到状态合法)  
        {  
            修改操作;//根据题意来添加  
            标记;  
            dfs();  
            (还原标记);  
            //是否还原标记根据题意  
            //如果加上(还原标记)就是 回溯法  
        }  
    }  
}

 bfs模板:

bfs搜索的流程可以理解成从一个点出发,往四周发散,计算机自动每次寻找最近的下一层,所以每一次标记的点都是通过最近的路径标记的点

void bfs()
{
	while(q.empty()==false)///队列非空
	{
		int x=q.front().first,y=q.front().second;//取出队首 
		q.pop();//队首出队
		for (int i=1;i<=n;i++)//n个方向 
		{
			int xx=x+dx[i],yy=y+dy[i];
			if (xx>=1 && xx<=n && yy>=1 && yy<=m && vis[xx][yy]==false) //未出界,未被访问过
			{
				vis[xx][yy]=true;//标记 
				q.push(make_pair(xx,yy));//入队
				ans[xx][yy]=ans[x][y]+1;//步数+1 
			} 
		} 
	} 
}

dfs走迷宫(二维数组搜索版)

#include<iostream>
using namespace std;
const int N=5;
int n=5;
bool vis[N][N]={false};//是否已经走过 
int tox=2,toy=4;//需要找到的点 
int maze[5][5]={
    {0,0,0,1,0},
    {0,1,0,1,0},
    {0,1,1,0,0},
    {0,1,1,0,1},
    {0,0,0,0,0},
};
int path[N*N][2];

bool able_to_reach=false;
int sx[5]={-1,0,1,0};//上右下左
int sy[5]={0,1,0,-1};
void dfs(int x,int y,int step){
	path[step][0]=x;
	path[step][1]=y;
	if(able_to_reach==true){
		return;
	}
	printf("%d %d\n",x,y);
	if(x==tox&&y==toy){
		able_to_reach=true;
		cout<<"找到了!";
		cout<<"路径"<<endl;
		for(int i=1;i<=step;i++){
			printf("x:%d,y:%d\n",path[i][0],path[i][1]);
		} 
		return;
	}
	int next_x,next_y; 
	for(int i=0;i<4;i++){
		next_x=x+sx[i];
	    next_y=y+sy[i];
	    //next point :next_x,next_y
	    if(next_x>=0&&next_x<n&&next_y>=0&&next_y<n&&vis[next_x][next_y]==false&&maze[next_x][next_y]==0){
	    	vis[next_x][next_y]=true;
	    	dfs(next_x,next_y,step+1);
	    	vis[next_x][next_y]=false;
		}
	}
}
int main(){
	vis[0][0]=true;
	dfs(0,0,1);
	return 0; 
}

是对着学长视频敲的,最基础的dfs了👆

深度优先搜索(dfs):用递归实现的方法用到了栈,规定一个固定的搜寻方向,将搜索到的存到栈中,若碰到不能实现的地方回溯(即出栈),直到能继续搜索直至搜索结束。

dfsP1605 迷宫

再做一道迷宫题:思路是一样的

#include <iostream>
using namespace std;
int n,m,t,sx,sy,fx,fy;int a[6][6];int sum;
int x1[]={0,0,1,-1};
int y1[]={1,-1,0,0};
void dfs(int x,int y){
	if(x==fx&&y==fy){
		sum++;
		return;
	}
	for(int i=0;i<4;i++){
		if(x+x1[i]>=1&&x+x1[i]<=n&&y+y1[i]>=1&&y+y1[i]<=m&&!a[x+x1[i]][y+y1[i]])
		{
			a[x+x1[i]][y+y1[i]]=1;
			dfs(x+x1[i],y+y1[i]);
			a[x+x1[i]][y+y1[i]]=0;
		}
	}
}
int main()
{
	int z,h;
	cin>>n>>m>>t>>sx>>sy>>fx>>fy;
	for(int i=0;i<t;i++){
		cin>>z>>h;
		a[z][h]=1;
	}
	a[sx][sy]=1;
	dfs(sx,sy);
	cout<<sum;
	return 0;
}

dfsP1706 全排列问题(经典例题)

#include <iostream>
using namespace std;
int n;int a[100];
bool b[100]={0};
void dfs(int shu){
	for(int i=1;i<=n;i++){
		if(b[i]==false){
			a[shu]=i;
			b[i]=true;
			dfs(shu+1);
			b[i]=false;
		}
	}
	if(shu==n+1){
		for(int i=1;i<n;i++){
			cout<<"    "<<a[i];
		}
		cout<<"    "<<a[n]<<endl;
		return;
	}
}
int main()
{
	cin>>n;
	dfs(1);
	return 0;
}

全排列n项可以理解为第一项取1到n的数,然后剩下一个n-1项的全排列,所以使用递归实现

写一个dfs的函数:每一层从1遍历到n,对已经选上的数字标记,一层层选出没被标记的数字。

在满足输出之后通过每一个递归分支把每一个数标记去掉,然后输出这一组数。

&  next_permutation方法:

next_permutation是按照字典序找到下一个排列并替代原有序列,下面简单测试它的用法

#include<iostream>
#include<algorithm>
using namespace std;
int main(){
	int a[3]={0,1,4};
	for(int i=0;i<3;i++){
		next_permutation(a,a+3);
		for(int j=0;j<3;j++)cout<<a[j]<<" ";
		cout<<endl;
	}
	return 0;
}

 这个在algorithm库里面的函数可以积累下来,在这个题目里面可以这么用它:

#include<iostream>
#include<algorithm>
using namespace std;
int main(){
	int n;cin>>n;
	int a[n];
	for(int i=0;i<n;i++)a[i]=i+1;
	int sum=1;
	for(int i=1;i<=n;i++)sum*=i;
	for(int i=0;i<sum;i++){
		for(int j=0;j<n;j++)cout<<"    "<<a[j];
		cout<<endl;
		next_permutation(a,a+n);
	}
	return 0;
}

 dfs+bfsP1135 奇怪的电梯

 dfs有个点超时了哎:

#include<iostream>
using namespace std;
const int N=1e5;
int n,a,b;//n表示楼层数,a表示出发楼层,b表示结束楼层
int x[N];//记录数量
bool vis[N]={0};//记录是否走过
int sum=N;
void dfs(int aa,int sum_b){//aa表示当前所在位置,sum_b表示当前递归所在分支走过的步数
	if(aa==b)sum=min(sum,sum_b);
	if(sum<sum_b)return;
	vis[aa]=1;
	if(aa+x[aa]<=n&&!vis[aa+x[aa]])dfs(aa+x[aa],sum_b+1);
	if(aa-x[aa]>=1&&!vis[aa-x[aa]])dfs(aa-x[aa],sum_b+1);
	vis[aa]=0;
}

int main(){
	cin>>n>>a>>b;
	for(int i=1;i<=n;i++)cin>>x[i];
	vis[a]=0;
	dfs(a,0);
	if(sum==N)cout<<"-1";
	else cout<<sum;
	return 0;
}

学完bfs后改造写的一个:

#include<iostream>
#include<queue>
#include<string.h>
using namespace std;
const int N=1e6;
queue<int>q;
int num[N];//记录数量
int w[N];//记录每层走的层数
bool vis[N]={0};//记录是否走过
int n,a,b;//n表示楼层数,a表示出发楼层,b表示结束楼层
void bfs(){
	while(!q.empty())
	{
		int s=q.front();
		q.pop();
		int f1=s+w[s];
		int f2=s-w[s];
		if(f1>=1&&vis[f1]==0)
		{
			vis[f1]=1;
			q.push(f1);
			num[f1]=num[s]+1;
		}
		if(f2>=1&&vis[f2]==0)
		{
			vis[f2]=1;
			q.push(f2);
			num[f2]=num[s]+1;
		}
	}
}
int main(){
	cin>>n>>a>>b;
	memset(num,-1,sizeof(num));
	for(int i=1;i<=n;i++)cin>>w[i];
	num[a]=0;vis[a]=1;
	q.push(a);
	bfs();
	if(num[b]==N)cout<<"-1";
	else cout<<num[b];
	return 0;
}

 注意两个地方:一个是memset-1那里要先初始化数组
                           还有一个是第一个出发点要给值,包括num=0和vis=1


bfsP1443 马的遍历

 队列:

入队:如q.push(x):将x元素接到队列的末端;
出队:如q.pop() 弹出队列的第一个元素,并不会返回元素的值;
访问队首元素:如q.front()
访问队尾元素:如q.back();
访问队中的元素个数:如q.size();
判断队列是否为空:q.empty()

memset函数:                                                                                                         

void *memset(void *s, int ch, size_t n);                                                                   

函数解释:将s中当前位置后面的n个字节用 ch 替换并返回 s 。作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法

代码实现:

#include<iostream>
#include<queue>
#include<algorithm>
#include<string.h>
using namespace std;
int n,m,x,y;//n*m的棋盘,在(x,y)处有一个马
queue<pair<int,int> >q;//定义一个队列
int a[405][405];//记录每个点所用步数
int vis[405][405];//记录每个点是否走过
int nx[9]={0,2,2,1,1,-1,-1,-2,-2};//x方向的走法
int ny[9]={0,1,-1,2,-2,2,-2,1,-1};//y方向的走法
void bfs(){
	while(!q.empty())//在队列中还有元素时
	{
		x=q.front().first;//先访问队首元素,由于是一个pair容器,通过.first访问到第一个元素即x
		y=q.front().second;//访问到当前的y
		q.pop();//把存下来的x和y这一对点出队列
		for(int i=1;i<=8;i++){
			int fx=x+nx[i];
			int fy=y+ny[i];
			if(fx>=1&&fy>=1&&fx<=n&&fy<=m&&vis[fx][fy]==0)
			{
				vis[fx][fy]=1;
				q.push(make_pair(fx,fy));//把下一个数入队列
				a[fx][fy]=a[x][y]+1;//对应每次的入队出队,进队的那个数即走到的那个数应该比出队的那个数步数多1
			}
		}
		
	}
}

int main(){
	cin>>n>>m>>x>>y;
	memset(a,-1,sizeof(a));
	a[x][y]=0;vis[x][y]=1;
	q.push(make_pair(x,y));
	bfs();
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++)printf("%5d",a[i][j]);
		cout<<endl;
	}
	return 0;
}

P1141 01迷宫

第一次完全做的时候如下,用dfs做的,也没有考虑所给数据存迷宫时的数字连在一起了 
后来改了一下之后:
自己给数据测试基本上是对的,方法肯定没问题。

#include<iostream>
#include<string.h>
using namespace std;
const int N=1e3+5;
int n,m;//n*n的迷宫  m个需要求的数据
char a[N][N];//存迷宫
int ans;//存答案
int vis[N][N]={0};//记录是否走过
int v[N][N]={0};//记录所有走过的点
int xx[4]={0,0,1,-1};
int yy[4]={1,-1,0,0};
void dfs(int x,int y){
	for(int i=0;i<4;i++){
		if(x+xx[i]>=0&&x+xx[i]<n&&y+yy[i]>=0&&y+yy[i]<n&&!vis[x+xx[i]][y+yy[i]]&&a[x][y]!=a[x+xx[i]][y+yy[i]])
		{
			vis[x+xx[i]][y+yy[i]]=1;
			v[x+xx[i]][y+yy[i]]=1;
			dfs(x+xx[i],y+yy[i]);
			vis[x+xx[i]][y+yy[i]]=0;
		}
	}
}
int main(){
	cin>>n>>m;
	for(int i=0;i<n;i++)
			cin>>a[i];
	for(int i=0;i<m;i++){
		int x,y;
		cin>>x>>y;
		x--;y--;
		ans=0;
		memset(vis,0,sizeof(vis));
		memset(v,0,sizeof(v));
		vis[x][y]=1;
		v[x][y]=1;
		dfs(x,y);
		for(int i=0;i<n;i++)
			for(int j=0;j<n;j++)
				if(v[i][j]==1)ans++;
				cout<<ans<<endl;
		
	}
	
	return 0;
}

不知道为啥超时但是还是超时了,下面换bfs做:

#include<iostream>
#include<string.h>
#include<queue>
using namespace std;
const int N=1e3+5;
int n,m;//n*n的迷宫  m个需要求的数据
char a[N][N];//存迷宫
int ans;//存答案
int vis[N][N]={0};//记录是否走过
int v[N][N]={0};//记录所有走过的点
int xx[4]={0,0,1,-1};
int yy[4]={1,-1,0,0};
queue<pair<int,int> >q;
void bfs(){
	while(!q.empty()){
		int x=q.front().first;
		int y=q.front().second;
		q.pop();
		for(int i=0;i<4;i++){
			if(x+xx[i]>=0&&x+xx[i]<n&&y+yy[i]>=0&&y+yy[i]<n&&!vis[x+xx[i]][y+yy[i]]&&a[x][y]!=a[x+xx[i]][y+yy[i]])
			{
				vis[x+xx[i]][y+yy[i]]=1;
				v[x+xx[i]][y+yy[i]]=1;
				q.push(make_pair(x+xx[i],y+yy[i]));
			}
		}
	}
}
int main(){
	cin>>n>>m;
	for(int i=0;i<n;i++)
			cin>>a[i];
	for(int i=0;i<m;i++){
		int x,y;
		cin>>x>>y;
		x--;y--;
		ans=0;
		memset(vis,0,sizeof(vis));
		memset(v,0,sizeof(v));
		q.push(make_pair(x,y));
		vis[x][y]=1;
		v[x][y]=1;
		bfs();
		for(int i=0;i<n;i++)
			for(int j=0;j<n;j++)
				if(v[i][j]==1)ans++;
				cout<<ans<<endl;
	}
	return 0;
}

 稍微好了那么一点点

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值