题目链接:传送门(点我)
方法一:广搜
分析:这题数据范围有点大,朴素广搜肯定不行。但用广搜仍然能做。
首先我们对于能打通的一大块进行染色(编号),脑补扫雷的画面。每一次广搜相当于打通一片。
然后对每个连通块进行个数统计即可。
AC代码
#include<bits/stdc++.h>
using namespace std;
#define MAXN 1010
int n,m,color=1;
int xx[4]={1,-1,0,0},yy[4]={0,0,-1,1};
char mp[MAXN][MAXN];
int vis[MAXN][MAXN],ans[MAXN*MAXN];
struct pos{
int x,y;
};
int bfs(int x,int y)//每一次广搜相当于打通一片连通块
{
int sum=1;
queue<pos>q;
pos s;s.x=x;s.y=y;//start
vis[s.x][s.y]=color;
q.push(s);
while(q.size()!=0){
pos t =q.front();
q.pop();
for(int i=0;i<4;i++){
pos z;
z.x=t.x+xx[i];z.y=t.y+yy[i];
if(z.x<1||z.x>n||z.y<1||z.y>n||vis[z.x][z.y]||mp[t.x][t.y]==mp[z.x][z.y])continue;
vis[z.x][z.y]=color;//染色
sum++;//当前联通块中方格的个数
q.push(z);
}
}
return sum;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
cin>>mp[i][j];
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(!vis[i][j]){ans[color]=bfs(i,j);color++;}
while(m--){
int x,y;
cin>>x>>y;
cout<<ans[vis[x][y]]<<endl;
}
return 0;
}
方法二:并查集
分析:既然是统计连通块中的个数,并查集当然再合适不过了。
AC代码
#include<bits/stdc++.h>
using namespace std;
#define MAXN 1010
int n,m,a,b;
int xx[4]={1,-1,0,0},yy[4]={0,0,-1,1};
char mp[MAXN][MAXN];
int p[MAXN*MAXN],cnt[MAXN*MAXN];//parent count
int f(int x){return p[x]==x?x:p[x]=f(p[x]);}//find root and compressed path
int mapping(int x,int y){return (x-1)*n+y;}//mapping
int main()
{
cin>>n>>m;
for(int i=1;i<=n*n;i++)p[i]=i,cnt[i]=1;//init
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)cin>>mp[i][j];//init map
//disjoint set
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
for(int k=0;k<4;k++){
int tx,ty;
tx=i+xx[k];ty=j+yy[k];
if(tx<1||tx>n||ty<1||ty>n||mp[tx][ty]==mp[i][j])continue;
int root_a = f(mapping(i,j));
int root_b = f(mapping(tx,ty));
if(root_a!=root_b){p[root_a]=root_b;cnt[root_b]+=cnt[root_a];}//merge
}
}
}
while(m--){
cin>>a>>b;
cout<<cnt[f(mapping(a,b))]<<endl;
}
return 0;
}