CodeForces-690#D1 题解

正文

很显然啊,这是在考一个叫连通块的东东,于是蒟蒻的我马上想到了连通块必备:并查集。

如果一个块四边连通了其它的块,那么合并这两个块。

当然,并查集要用二维的:

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: 发布

posted @ 2022-12-27 19:51  IOIAK_wanguan  阅读(43)  评论(0)    收藏  举报