程序设计中两种相对简单常用的搜索:深度搜索和广度搜索

文章讲述了深度优先搜索(DFS)和广度优先搜索(BFS)在编程中的应用,尤其是在处理条件复杂的问题时,如何通过剪枝优化算法效率。以洛谷题目为例,展示了DFS在数独和火车问题中的应用,以及BFS在最少步数问题中的选择。
摘要由CSDN通过智能技术生成

搜索

分为深度优先搜索DFS(Deep First Search)和广度优先搜索BFS(Breath First Search),重点在于剪枝,适用于因为条件过多而难以正常处理的环境,编码时需要大量的检验点来保障准确性

DFS

深度优先搜索适合判断能不能到某一个地方,特点是状态回溯和剪枝,在有多少种方法和能否判断上比BFS有优势

洛谷 P1784 数独
#include<bits/stdc++.h>
using namespace std;
#define foo(i,a,b) for(int i=a;i<b;i++)
#define fio(i,a,b) for(int i=a;i>b;i--)
const int N=11;

bool check[N][N],b[N][N],c[N][N],d[N][N]; //b指第i行j出没出现过,c指的是列,d值得是块 
int a[N][N];

int reflect(int x,int y)
{
	return (x-1)/3*3+(y-1)/3+1;//判断分区
}

void print(void)
{
	foo(i,1,10)
	{
		foo(j,1,10)
		{
			cout<<a[i][j]<<" ";
		}
		cout<<"\n";
	}
	cout<<"\n";
}

void dfs(int x,int y)//这里用bfs要比dfs慢,因为bfs遍历的比dfs多
{
	if(check[x][y])//判断有没有被填过
	{
		if(x==9&&y==9)
		{
			print();
			return;
		}
		if(y==9)
		{
			dfs(x+1,1);
			return;
		}
		else
		{
			dfs(x,y+1);
			return;
		}
	}
	foo(i,1,10)//这里从1到9不会有重合的可能,不需要剪枝
	{
		if(!b[x][i]&&!c[y][i]&&!d[reflect(x,y)][i])
		{
			a[x][y]=i;//猜测
			b[x][i]=1,c[y][i]=1,d[reflect(x,y)][i]=1;
			if(x==9&&y==9)print();
			else if(y==9)dfs(x+1,1);
			else dfs(x,y+1);
			a[x][y]=0;//猜测失败,状态回溯
			b[x][i]=0,c[y][i]=0,d[reflect(x,y)][i]=0;
		}
	}
}

signed main()
{
	ios::sync_with_stdio(0);
	foo(i,1,10)
	{
		foo(j,1,10)
		{
			cin>>a[i][j];
			if(a[i][j])
			{
				b[i][a[i][j]]=1;
				c[j][a[i][j]]=1;
				d[reflect(i,j)][a[i][j]]=1;
				check[i][j]=1;
			}
		}
	}
	dfs(1,1);
	return 0;
}
洛谷 Phillip and Trains 
#include<bits/stdc++.h>
using namespace std;
#define foo(i,a,b) for(int i=a;i<b;i++)
#define fio(i,a,b) for(int i=a;i>b;i--)
const int N=105;
int t,n,k;
bool a[4][N],flag; 

void dfs(int x,int y)//用dfs因为找能不能出去,而不是最短几步出去,在这种条件下dfs优于bfs
{
	if(y>=n&&flag==false)
	{
		cout<<"YES"<<endl;
		flag=true;
		return;
	}
	if(flag)return;
	if(!a[x][y+1])
	{
		if(x+1<3&&!a[x+1][y+1]&&!a[x+1][y+2]&&!a[x+1][y+3])
		{
			dfs(x+1,y+3);
		}
		if(!a[x][y+2]&&!a[x][y+3])
		{
			dfs(x,y+3);
		}
		if(x-1>=0&&!a[x-1][y+1]&&!a[x-1][y+2]&&!a[x-1][y+3])
		{
			dfs(x-1,y+3);
		}
	}
}

signed main()
{
	ios::sync_with_stdio(0);
	cin>>t;
	int nback=0;
	char a_;
	int x,y;
	while(t--)
	{
		flag=false;
		cin>>n>>k;
		nback=n;
		foo(i,0,3)
		{
			foo(j,0,n)
			{
				cin>>a_;
				if(a_=='s')x=i,y=j;
				else if(a_=='.') ;
				else a[i][j]=1;
			}
		}
		dfs(x,y);
		if(!flag)cout<<"NO"<<endl;
		memset(a,0,sizeof(a));
	}
	return 0;
}

BFS

广搜的数据记录一般用队列的形式,剪枝用数组,map函数容易爆,在最小步数问题中搜索算法只能用bfs

洛谷 P1379 八数码难题
#include<bits/stdc++.h>
using namespace std;
#define foo(i,a,b) for(int i=a;i<b;i++)
#define fio(i,a,b) for(int i=a;i>b;i--)
const int N=130;

struct A
{
	int a[3][3];
	int x,y;
	int steps;
};
int b[3][3];

bool check(A B)
{
	foo(i,0,3)
	{
		foo(j,0,3)
		{
			if(B.a[i][j]!=b[i][j])
			{
				return false;
			}
		}
	}
	return true;
}
int c[]={1,0,-1,0};
int d[]={0,1,0,-1};
string m="123804765";

signed main()
{
	ios::sync_with_stdio(0);
	A tempa,tt;
	foo(i,0,3)foo(j,0,3)tempa.a[i][j]=int(m[i*3+j])-int('0');
	tempa.x=1,tempa.y=1,tempa.steps=0;
	cin>>m;
	foo(i,0,3)
	{
		foo(j,0,3)
		{
			b[i][j]=int(m[i*3+j])-int('0');
		}
	}
	queue<A> q;
	q.push(tempa);
	while(!q.empty())
	{
		tempa=q.front();
		if(check(tempa))
		{
			cout<<tempa.steps;
			break;
		}
		q.pop();
		foo(i,0,4)
		{
			tt=tempa;
			tt.steps++;
			if(tt.x+c[i]<3&&tt.x+c[i]>=0&&tt.y+d[i]<3&&tt.y+d[i]>=0)
			{
				swap(tt.a[tt.x][tt.y],tt.a[tt.x+c[i]][tt.y+d[i]]);
				tt.x+=c[i];
				tt.y+=d[i];
				if(check(tt))
				{
					cout<<tempa.steps+1;
					exit(0);//表示正常退出代码
				}
				q.push(tt);
				swap(tt.a[tt.x][tt.y],tt.a[tt.x-c[i]][tt.y-d[i]]);
			}
		}
	}
	return 0;
}
洛谷 P1443 马的遍历
#include<bits/stdc++.h>
using namespace std;
#define foo(i,a,b) for(int i=a;i<b;i++)
#define fio(i,a,b) for(int i=a;i>b;i--)
#define mp make_pair
const int N=500;

int n,m,x,y;
int a[N][N];
bool b[N][N];//这里的剪枝是这道题的关键
int op[][2]={{-2,-1},{-2,1},{-1,-2},{-1,2},{2,-1},{2,1},{1,2},{1,-2}};
struct biao
{
	int x,y;
	int cnt;
};

signed main()
{
	scanf("%d%d%d%d",&n,&m,&x,&y);
	foo(i,1,n+1)
	{
		foo(j,1,m+1)
		{
			a[i][j]=-1;
		}
	}
	queue<biao> q;
	biao temp;
	temp.x=x;
	temp.y=y;
	temp.cnt=0;
	q.push(temp);
	a[x][y]=temp.cnt;
	b[x][y]=1;
	int tempx,tempy,cnt;
	while(!q.empty())
	{
		tempx=q.front().x,tempy=q.front().y,cnt=q.front().cnt;
		q.pop();
		foo(i,0,8)
		{
			if(tempx+op[i][0]>=1&&tempx+op[i][0]<=n&&tempy+op[i][1]>=1&&tempy+op[i][1]<=m&&!b[tempx+op[i][0]][tempy+op[i][1]])//注意这里是一和零 
			{
				temp.x=tempx+op[i][0],temp.y=tempy+op[i][1],temp.cnt=cnt+1;
				q.push(temp);
				a[temp.x][temp.y]=temp.cnt;
				b[temp.x][temp.y]=1;
			}
		}
	}
	foo(i,1,n+1)
	{
		foo(j,1,m+1)
		{
			printf("%-5d",a[i][j]);
		}
		printf("\n");
	}
	return 0;
}
  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值