题解:B4286 [蓝桥杯青少年组省赛 2022] 农作物
闲话
我被线段树肘飞后,就来这里找回对数据结构题的信心了。
思路
本题就是找连通块,所以深搜 , 广搜 , 还有并查集都可以。
这里我用深搜,因为我广搜写炸了。
深搜整体过程
- 判断这个点是不是田地。
- 进入深搜并把答案加一(因为这是一个新的连通块)。
- 把自己变成杂草(防止重复搜索)。
- 查看四周是不是田地。
- 搜索下一个田地并回到第三步。
深搜整体代码:
#include<bits/stdc++.h>
using namespace std;
int n,m;
char a[515][515]={};
long long sum=0;
int fx[8]={1,-1,0,0};
int fy[8]={0,0,1,-1};
void dfs(int x,int y){
a[x][y]='X';
int x_x=0;
int x_y=0;
for(int i=0;i<4;i++){
int x_x=x+fx[i];
int x_y=y+fy[i];
if(x_x<=n&&x_x>=1&&x_y<=m&&x_y>=1){
if(a[x_x][x_y]=='R'){
dfs(x_x,x_y);
}
}
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>a[i][j];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(a[i][j]=='R'){
sum++;
dfs(i,j);
}
}
}
cout<<sum;
}
并查集整体思路
这道题一眼并查集求联通块。高级数据结构已学魔怔。
首先这道题的并查集要一维化 ,那么如何一维化呢?那当然是 \((i-1)\times m+j\) 啦( \(i\) 表示行数,\(j\) 表示列数)。
接下来遍历数组,如果是田地,就去看看四周有没有田地,如果有就合并。
最后统计有几个田地是根节点就是联通块的个数。
如果是不知道什么是并查集的新手可以去看看这篇生动又形象的并查集教学。
并查集整体代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int n,m,ans=0;
int fa[N];
char dt[515][515];
int find(int x){//查询+压缩路径
return fa[x]==x ? x : fa[x]=find(fa[x]);//三目运算符大法好
}
void add(int x,int y){//合并操作
int nx=find(x);
int ny=find(y);
if(nx!=ny) fa[nx]=ny;
}
int main(){
cin>>n>>m;
for(int i=1;i<=n*m;i++){//初始化
fa[i]=i;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>dt[i][j];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(dt[i][j]=='R'){
int id=(i-1)*m+j;
if(dt[i][j-1]=='R'&&j>1){
add(id,(i-1)*m+j-1);
}
if(dt[i-1][j]=='R'&&i>1){
add(id,(i-2)*m+j);
}
if(dt[i+1][j]=='R'&&i<n){
add(id,i*m+j);
}
if(dt[i][j+1]=='R'&&j<m){
add(id,(i-1)*m+j+1);
}//观察四周
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
int id=(i-1)*m+j;
// cout<<setw(3)<<fa[(i-1)*m+j]<<" ";//调试时让场宽一致,方便观察。
if(fa[id]==id&&dt[i][j]=='R') ans++;
}//cout<<"\n";
}
cout<<ans;
}
后记
膜拜 @yuruilin2026 大佬对我的并查集的教导。