目录
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;
}