算法笔记 深度优先搜索(DFS)和广度优先搜索(BFS)

深度优先搜索(DFS)和广度优先搜索(BFS)

深度优先搜索(一种枚举所有完整路径以遍历所有情况的搜索方法 )

在这里插入图片描述
在这里插入图片描述

例题:
在这里插入图片描述


#include<cstdio>
const int maxn = 30;
int n,V,maxValue = 0;		//物品件数n,背包容量V,最大价值maxValue
int w[maxn],c[maxn];		//w[i]为每件物品的重量, 
//DFS ,index为当前处理的物品编号
//sumW和sumC分别为当前总重量和当前总价值
void DFS(int index,int sumW,int sumC)
{
	if(index == n)	//已经完成对n件物品的选择(死胡同)
	{	
		if(sumW <= V && sumC>maxValue)
		{
			maxValue = sumC;		//不超过背包容量时更新最大加价值maxValue 
		} 
		return;
	}
	//岔道口
	DFS(index + 1,sumW,sumC);		//不选第index件物品    使用递归时,系统会调用一个叫系统栈的东西来存放递归中每一层的状态 
	DFS(index + 1,sumW+w[index],sumC+c[index]);		//选第index件物品 
}

int main()
{
	scanf("%d%d",&n,&V);
	for(int i=0;i<n;i++)
	{
		scanf("%d",&w[i]);		//每件物品的重量 
	}
	
	for(int i=0;i<n;i++)
	{
		scanf("%d",&c[i]);		//每件物品的重量 
	}
	DFS(0,0,0);					//初始时为第0件物品、当前总重量和总价值均为0
	printf("%d\n",maxValue); 
	return 0;
}


上述代码中,总是把n件物品的选择全部确定之后才去更新最大价值,但忽略了背包容量不超过V这个特点。
优化:只有sumW<=V时才进入岔道(剪枝)

//DFS ,index为当前处理的物品编号
//sumW和sumC分别为当前总重量和当前总价值
void DFS(int index,int sumW,int sumC)
{
	if(index == n)	//已经完成对n件物品的选择(死胡同)
	{	
		return;
	}
	//岔道口
	DFS(index + 1,sumW,sumC);		//不选第index件物品    使用递归时,系统会调用一个叫系统栈的东西来存放递归中每一层的状态 
	if(sumW + w[index] <= V)
	{
		if(sumC+c[index]>ans)
		{
			ans=sumC+c[index];			//更新最大价值maxValue 
		}
		DFS(index + 1,sumW+w[index],sumC+c[index]);		//选第index件物品 
    }
}


广度优先搜索

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述在这里插入图片描述在这里插入图片描述

#include<cstdio>
#include<queue>
using namespace std;
const int maxn = 100;

struct node{
	int x,y;
}Node;

int n,m;						//矩阵大小为n*m 
int matrix[maxn][maxn]; 		//01矩阵 
bool inq[maxn][maxn] = {false};  		//记录位置(x,y)是否已入过队 而不是结点是否已被访问 

int X[4] = {0,0,1,-1};			//增量数组
int Y[4] = {1,-1,0,0};

bool judge(int x,int y)         //判断坐标(x,y)是否需要访问
{		
	//越界返回false
	if(x>=n||x<0||y>=m||y<0) return false;
	//当前位置为0,或(x,y)已入过队,返回false 
	if(matrix[x][y] == 0 || inq[x][y] == true)  return false;
	return true;
} 

//BFS函数访问位置(x,y)所在的块,将该块中所在“1”的inq都设置为true
void BFS(int x,int y)
{
	queue<node> Q;			//定义队列 
	Node.x = x, Node.y=y;	//当前结点的坐标为(x,y) 
	Q.push(Node);			//将结点Node入队 
	inq[x][y] = true;		//设置(x,y)已入过队
	while(!Q.empty())
	{
		node top = Q.front();		//取出队首元素
		Q.pop();					//队首元素出队
		for(int i=0;i<4;i++)		//循环4次,得到4个相邻位置 
		{
			int newX = top.x + X[i];
			int newY = top.y + Y[i];
			if(judge(newX,newY))	//如果新位置(newX,newY)需要访问 
			{
				//设置Node的坐标为(newX,newY)
				Node.x = newX, Node.y = newY;
				Q.push(Node);		//将结点Node加入队列 	
				inq[newX][newY] = true;		//设置位置(newX,newY)已入过队 
			} 
		} 
	 } 
} 
	
int main()
{
	scanf("%d%d",&n,&m);
	for(int x=0;x<n;x++)
	{
		for(int y=0;y<m;y++)
		{
			scanf("%d",&matrix[x][y]);			//读入0 1矩阵
		}
	} 
	int ans = 0;		//存放块数
	for(int x=0;x<n;x++)
	{
		for(int y=0;y<m;y++)
		{
			//如果元素为1,且未入过队 
			if(matrix[x][y]==1 && inq[x][y] == false)
			{
				ans++;		//块数加1
				BFS(x,y);	//访问整个块,将该块所有“1”的inq都标记为true 
			}
		 } 
	 } 
	printf("%d\n",ans);
	return 0;
 } 


在这里插入图片描述
例子:
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int maxn = 100;

struct node{
	int x,y;	//位置(x,y) 
	int step; 	//起点S到达该位置的最小步数(即层数) 
}S,T,Node;		//S为起点,T为终点,Node为临时结点 

int n,m;						//矩阵大小为n*m 
char maze[maxn][maxn]; 		//迷宫信息 
bool inq[maxn][maxn] = {false};  		//记录位置(x,y)是否已入过队 而不是结点是否已被访问 

int X[4] = {0,0,1,-1};			//增量数组
int Y[4] = {1,-1,0,0};

//检测位置(x,y)是否有效
bool test(int x,int y)         
{		
	//越界返回false
	if(x>=n||x<0||y>=m||y<0) return false;
	//当墙壁* 或(x,y)已入过队,返回false 
	if(maze[x][y] == '*' || inq[x][y] == true)  return false;
	return true;	//有效位置 
} 


int BFS()
{
	queue<node> q;			//定义队列 
	q.push(S);			//将结点Node入队 
	while(!q.empty())
	{
		node top = q.front();		//取出队首元素
		q.pop();					//队首元素出队
		if(top.x == T.x && top.y == T.y)
		{
			return top.step;	//终点,返回最小步数 
		}
		
		for(int i=0;i<4;i++)		//循环4次,得到4个相邻位置 
		{
			int newX = top.x + X[i];
			int newY = top.y + Y[i];
			if(test(newX,newY))	//如果位置(newX,newY)有效 
			{
				//设置Node的坐标为(newX,newY)
				Node.x = newX, Node.y = newY;
				Node.step = top.step +1;	//Node层数为top的层数+1 
				q.push(Node);		//将结点Node加入队列 	
				inq[newX][newY] = true;		//设置位置(newX,newY)已入过队 
			} 
		} 
	 } 
 	return -1;	//无法到达终点T返回-1 
}
 
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=0;i<n;i++)
	{
		getchar();		// 过滤掉每行后面的换行符   getchar可以识别换行符
		for(int j=0;j<m;j++)
		{
			maze[i][j]=getchar();
		}
		maze[i][m+1]='\0';
	} 
	scanf("%d%d%d%d",&S.x,&S.y,&T.x,&T.y);	//起点和终点的坐标
	S.step = 0; 		//初始化起点的层数为0,即S到S的最小步数为0
	printf("%d\n",BFS()); 
	return 0;
 } 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值