算法学习之路的心得一之搜索,二分

本文详细介绍了深度优先搜索(DFS)和广度优先搜索(BFS)的概念,分别给出了它们的C++实现模板,并通过两个实例题目——LakeCounting和RedandBlack展示了它们在解决实际问题中的应用。此外,还探讨了二分查找的基本思想,提供了二分查找的模板,并讨论了如何在C++中使用内置的二分函数。这些算法在图论和搜索问题中具有广泛的应用。

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

GDUT 20 寒假集训专题1.dfs/bfs+二分

  1. 总结

  2. 题目题解

1.dfs/bfs

dfs以“能走多远就走多远"为基本原则,是非常重要的一种搜索方法。

这里有一个在洛谷看到的dfs模板

int search(int t)
{
    if(满足输出条件)
    {
        输出解;
    }
    else
    {
        for(int i=1;i<=尝试方法数;i++)
            if(满足进一步搜索条件)
            {
                为进一步搜索所需要的状态打上标记;
                search(t+1);
                恢复到打标记前的状态;//也就是说的{回溯一步}
            }
    }
}

相对的bfs就先尽可能的搜索与已搜索顶点相邻的未搜索顶点,然后以此类推不断扩大搜索范围,常用来求最短路径。

下面是用图+队列来实现bfs的代码

计算每个顶点到开始顶点的最短路径

int G[105][105],color[105],d[105],n,t;//color是状态,0表示未曾进队,1表示在队列中,2表示出队列      数组d是各顶点到开始顶点的最短距离
void bfs(int u)
{
		queue <int > Q;
		d[u]=0;
		color[u]=1;
		Q.push(u);
		int v;
		while(!Q.empty() ){
			u=Q.front() ;Q.pop() ;
			color[u]=2;
			for(int i=1;i<=n;i++){
				if(G[u][i]==1&&color[i]==0){
					Q.push(i);
					d[i]=d[u]+1;
					color[i]=1; 
				}
			}
		} 
}

2.二分

二分的包括二分查找以及二分答案等等…

这里是二分查找的模板

int bin(int *a,int size,int p)
{
	int l=0;
	int r=size-1;
	while(l<=r){
		int mid=l+(r-l)/2;
		if(p==a[mid]){
			return mid;
		}
		else if(p>a[mid]){
			l=mid+1;
		}
		else{
			r=mid-1;
		}
	}
	return -1;
}

如果是用c++,c++的algorithm里面有几个二分函数

具体调用如下

#include <algorithm>
int coun(int l,int r)	//包含端点
{
	int *s,*f,p;
	s=lower_bound(mei,mei+d,l); //下界,第一个大于等于l
	f=upper_bound(mei,mei+d,r);//上界,第一个大于r的元素
	p=f-s;
	return p;
}

善于运用这两个二分查找,其实可以用来查找一个区间的数,就是用上述代码实现的

二分答案也有模板,具体如下

int bin(int *a,int size,int p)
{
	int l=0,ans;
	int r=size-1;
	while(l<=r){
		int mid=l+(r-l)/2;
		if(judge(mid)){    //这里就是写一个判断的函数,判断mid是否符合题意,是就返回1,否
			ans=mid;	  //就返回0
            l=mid+1; //是变大还是变小需要根据题目的要求来变化
		}
		else{
			r=mid-1;
		}
	}
	cout<<ans;
}

接下来贴两道相关的题目

1.Lake Counting

题目链接

题目描述:由于最近的降雨,水在农民约翰的田地的不同地方聚集,这是一个矩形N x M (1 <= N <= 100;1 <= M <= 100)正方形。每个正方形要么包含水(‘W’),要么包含旱地(’.’)。农民约翰想算出他的田地里已经形成了多少个池塘。池塘是一组相连的有水的广场,一个广场被认为是相邻的所有8个邻居。给农民约翰的田地一张图,算出他有多少个池塘。

解题思路:这道题用dfs,bfs应该都行,我用的是dfs,开二维数组把图存下来,把旱地标为0,水地标为1,先从第一个水地开始dfs,往八个方向一直搜索,能搜索到的地方都是属于这一个池塘,然后记为1个,并且把这时候搜索到的同属第一个池塘的所有水地改成旱地,然后继续执行上一步,直到所有地方都变成旱地,答案也就出来了。

ac代码:

#include <iostream>
#include <stdio.h>
using namespace std;
int dx[8]={1,1,1,0,0,-1,-1,-1};
int dy[8]={0,1,-1,1,-1,0,1,-1};
int G[105][105],n,m,color[105][105],count;
void dfs(int x,int y)
{
		color[x][y]=0;
		G[x][y]=0;
		for(int i=0;i<8;i++){
			int nx=x+dx[i];
			int ny=y+dy[i];
			if(nx<0||ny<0||nx>=n||ny>=m){
				continue;
			}
			if(G[nx][ny]==1&&color[nx][ny]==1){
				dfs(nx,ny);
			}
		}
}
int main()
{
		int i,j;
		char ch;
		cin>>n>>m;
		getchar();
		for(i=0;i<n;i++){
			for(j=0;j<m;j++){
				color[i][j]=1;
				cin>>ch;
				if(ch=='.'){
					G[i][j]=0;
				}
				else {
					G[i][j]=1;
				}
			}
			getchar();
		}
		for(i=0;i<n;i++){
			for(j=0;j<m;j++){
				if(color[i][j]==1&&G[i][j]==1){
					dfs(i,j);
					count++;
				}
			}
		}
		cout<<count;
		return 0;
}

2.Red and Black

题目链接

题目描述:有一个长方形的房间,上面铺着方瓷砖。每个贴图都是红色或黑色。一个人站在一块黑瓷砖上。从一个贴图,他可以移动到四个相邻贴图中的一个。但是他不能在红色的贴图上移动,只能在黑色的贴图上移动。写一个程序来计算他通过重复上面描述的动作可以达到的黑色方块的数量。

解题思路:这一题我是用的bfs,同样的我用二维数组存下来整个图,把能走的黑色记为0,把不能走的红色记为1,也差不多是障碍物的意思。把开始的位置放入bfs函数里面,从这一点开始,把这一点入队,然后因为只有他一个点,所以进入循环他就出队了,出队之后把它四个方向并且能走的地方继续入队,同时统计入队个数,如此循环操作直到队列为空了,也就是没法再走了,答案也就出来了。

ac代码

#include <iostream>
#include <queue>
#include <stdio.h>
using namespace std;
struct node {
	int x,y;
};
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
int n,m,G[25][25],color[25][25],coun;

void bfs(int x,int y)
{
		struct node xy;
		xy.x=x;
		xy.y=y;
		coun++;
		color[x][y]=0;
		queue <node > Q;
		Q.push(xy);
		int nx,ny;
		while(!Q.empty()){
			xy=Q.front() ;Q.pop() ;
			x=xy.x;
			y=xy.y;
			for(int i=0;i<4;i++){
				nx=x+dx[i];
				ny=y+dy[i];
				if(nx<0||ny<0||nx>=n||ny>=m){
					continue;
				}
				if(G[nx][ny]==0&&color[nx][ny]==1){
					color[nx][ny]=0;
					coun++;
					xy.x=nx;
					xy.y=ny;
					Q.push(xy); 
				}
			}
		} 
}
int main()
{
		int i,j,x,y;
		char ch;
		cin>>m>>n;
		getchar();
		while(n!=0){
			for(i=0;i<n;i++){
				for(j=0;j<m;j++){
					color[i][j]=1;
					cin>>ch;
					if(ch=='.'){
						G[i][j]=0;
					}
					else if(ch=='#'){
						G[i][j]=1;
					}
					else {
						x=i;
						y=j;
					}
				}
				getchar();
			}
			coun=0;
			bfs(x,y);
			cout<<coun<<endl; 
			cin>>m>>n;
			getchar();
		}
		
		return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值