蓝桥杯真题——洛谷Day14 BFS 、思维

目录

bfs、模拟:

P8662 [蓝桥杯 2018 省 AB] 全球变暖

 代码:

思维题

P9421 [蓝桥杯 2023 国 B] 班级活动

代码: 

bfs、模拟:

P8662 [蓝桥杯 2018 省 AB] 全球变暖

思路

将岛屿看做一个个连通块,直接求会被淹没的连通块不好求,可使用反思维求出所有的连通块,减去不会被淹没的连通块

 当遍历由m个陆地组成的岛屿时,使用位移遍历数组

对于遍历到的点(i,j)的四个方向
对于行:左边为(i,j-1)右边为(i,j+1)
对于列:上为(i-1,j),下为(i+1,j)
即可设对应的位移变量数组,便于后续使用
行:h[]={0,-1,0,1}
列:l[]={-1,0,1,0}

如何记录不被淹没的岛屿

某个陆地周围有4个陆地即可记录该岛屿不被淹没

注意特殊情况:当该陆地处于角落时,数组越界的部分可看做是陆地

 代码:

#include<iostream>
#include<queue>

#define PII pair<int,int>//二维坐标组
 
using namespace std;

const int N=1000+10;
 
int n;
char g[N][N];//存储地图
bool st[N][N];//标记数组,是否遍历过某点
int dx[]={0,-1,0,1};//行
int dy[]={-1,0,1,0};//列
 
bool check(int x,int y)
{
	queue<PII> q;//使用队列进行遍历,因为此时的遍历情况具有先进先出的特性
	q.push({x,y});//二维数据入队需要使用大括号
	st[x][y]=1;//表示已经遍历
	int flag=0;//是否存在不被淹没的岛屿 
	
	while(q.size())//开始遍历队列,将前面放入的点的周围的点入队 
	{
		//重要步骤:起到循环队列的作用 
		// 后面如果将新的陆地入队,可以实现对每一个陆地的四周进行逐一遍历 
		PII t=q.front();//取出队头
		q.pop();
		
		if(!flag)
		{
			int tmp=0;//该陆地周围的陆地数
			for(int i=0;i<4;i++)
			{
				int a=dx[i]+t.first;
		 		int b=dy[i]+t.second;
		 		if(a<1||a>n||b<1||b>n)
				{	//特判:
					//当越界时对于此时是没有海洋的情况,可将其看做是陆地 
		 			tmp++;
		 			continue;
				 }
				if(g[a][b]=='#')
					tmp++;
			 } 
			 if(tmp==4)
			 	flag=1;
		}
		
		//枚举该点的上下左右四个方向,将其入队
		 for(int i=0;i<4;i++)//该循环的作用是将岛屿标记,使main函数对一个岛屿只便利一遍 
		 {
		 	int a=dx[i]+t.first;
		 	int b=dy[i]+t.second;
		 	if(a<1||a>n||b<1||b>n)//判断越界
		 		continue;
		 	if(st[a][b]) continue;
		 	if(g[a][b]=='.') continue;
		 	
		 	q.push({a,b});
		 	st[a][b]=1;
			  
		 }
	 } 
	 return flag==1;
}
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			cin>>g[i][j];
	int cnt1=0,cnt2=0;//不会被淹没的岛屿数  总共岛屿数
	
	//使用bfs进行搜索遍历
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			if(!st[i][j]&&g[i][j]=='#')//开始搜索的条件,没被遍历过&&是# 
			{
				if(check(i,j))
					cnt1++;//不会被淹没的岛屿++ 
				cnt2++;//总岛屿++ 
			}
		}
	 } 
	cout<<cnt2-cnt1<<endl;
	return 0;
 } 
 

思维题

P9421 [蓝桥杯 2023 国 B] 班级活动

 注意:

可能会出现情况:一个数字只有1个,或者一个数字有2个以上
这时需要统计两个不同的情况,即统计团体中多出来的人和落单的人

易错点

结果不能直接将(cnt1+cnt2)/2输出,会出错!!!!
需要对落单的人数和群体中的人数进行判断

假设落单的人多

将团体与落单的人配对,即cnt1+,在将剩下的落单的人抱团取暖,即(cnt2-cnt1)/2;输出式子:cnt1+(cnt2-cnt1)/2

假设团体人多
先将落单的人与团体配对,即cnt2,;再将团体剩余的人都修改(cnt1-cnt2);式子:cnt2+cnt1-cnt2=cnt1

代码: 

#include<iostream>
#include<map>

using namespace std;

const int N=1e5+10;

int n;
map<int,int> mp;//使用一个桶来存放数据 

int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		int x;cin>>x;
		mp[x]++;
	}
	int cnt1=0,cnt2=0;//团体中多出的人数  落单的人数
	for(auto i:mp)
	{
		if(i.second>=2)
			cnt1+=i.second-2;//团体中多出的人 
		else 
			cnt2++;//落单的人 
	 } 
	//注意不能直接将(cnt1+cnt2)/2直接输出
	//需要讨论哪个人数多 
	if(cnt2>=cnt1)//落单的人多 
		cout<<cnt1+(cnt2-cnt1)/2<<endl;
	else//团体人多 
		cout<<cnt1<<endl;
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值