正文
很显然啊,这是在考一个叫连通块的东东,于是蒟蒻的我马上想到了连通块必备:并查集。
如果一个块四边连通了其它的块,那么合并这两个块。
当然,并查集要用二维的:
typedef pair<int,int> pii;
pii f[1005][1005];
void init(){//初始化并查集
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)
f[i][j]={i,j};
}
pii fd(pii a){//查找根
if(f[a.fi][a.sc]==a) return a;
return f[a.fi][a.sc]=fd(f[a.fi][a.sc]);
}
void unio(pii a,pii b){//合并a和b所在的集合
f[a.fi][a.sc]=fd(b);
}
最后就是查重,这里我用了手打的哈希表 set
。
遍历并查集数组,将每个子节点的根节点放入 set
,去重,最后看 set
的元素数就可以。
struct set{
int s[1000005];
void insert(pii a){
s[a.fi*105+a.sc]++;
}
int size(){
int ret=0;
for(int &i:s)
if(i) ret++;
return ret;
}
};
最后综合:
#include<iostream>
#include<bits/stl_pair.h>
#define fi first
#define sc second
using namespace std;
typedef pair<int,int> pii;
pii f[1005][1005];
int n,m;
char a[1005][1005];
struct set{
int s[1000005];
void insert(pii a){
s[a.fi*105+a.sc]++;
}
int size(){
int ret=0;
for(int &i:s)
if(i) ret++;
return ret;
}
};
set s;
void init(){
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)
f[i][j]={i,j};
}
pii fd(pii a){
if(f[a.fi][a.sc]==a) return a;
return f[a.fi][a.sc]=fd(f[a.fi][a.sc]);
}
void unio(pii a,pii b){
f[a.fi][a.sc]=fd(b);
}
int main(){
ios::sync_with_stdio(false),cin.tie(0);
cin>>n>>m;
init();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
cin>>a[i][j];
if(a[i][j]=='.') continue;
if(a[i-1][j]=='B') unio({i-1,j},{i,j});
if(a[i+1][j]=='B') unio({i+1,j},{i,j});
if(a[i][j-1]=='B') unio({i,j-1},{i,j});
if(a[i][j+1]=='B') unio({i,j+1},{i,j});
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(a[i][j]=='B') s.insert(fd({i,j}));
cout<<s.size();
}
后附
日志
v1.0 on 2022.12.27: 发布
标签:pii,690,set,unio,int,题解,CodeForces,ret,1005 From: https://www.cnblogs.com/wanguan/p/17008864.html