这道题是对你bfs运用的高难度考察,这道题还有很多坑点,比如说他储存在a数组中的0和1不是常数而是字符,你还需要进一步将其转化为常数,如果做出来了因为这一点没ac就气死了,所以阅读题目的时候要认真。
这道题难点是你怎么在储存外岛的同时能区别这个岛是不是外环岛里面的内岛。而你可以用bfs来枚举外岛外面的外海同时对其进行标记,如果外海没法和内海相连接,就说明遇到了环岛,而我们这样就不用进一步再寻找环岛内的内岛。当我们在枚举外海时遇见了岛屿,再用bfs来枚举岛屿,进行标记,知道哪些岛是连在一起的。
这题还得注意海是可以从八个方向进行枚举的。
岛屿个数,具体代码如下:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int N=51;
int a[N][N];
int t,n,m;
int v1[N][N];
int v2[N][N];//两个标记数组
int ans=0;
int idx1[4]={0,0,1,-1},idy1[4]={1,-1,0,0};
int idx2[8]={0,0,1,-1,1,1,-1,-1},idy2[8]={1,-1,0,0,1,-1,-1,1};
bool check(int x,int y)
{
if(x>=0&&y>=0&&x<n&&y<m)
return true;
return false;
}
void bfs1(int x,int y)
{
queue<pair<int,int>> q;
q.push({x,y});
v1[x][y]=1;
while(q.size())
{
auto t=q.front();
q.pop();
for(int i=0;i<4;i++)
{
int xx=t.first+idx1[i],yy=t.second+idy1[i];
if(check(xx,yy)&&v1[xx][yy]==0&&a[xx][yy]==1)
{
v1[xx][yy]=1;
q.push({xx,yy});
}
}
}
}//对遇见的岛屿及其连在一起的岛进行标记
void bfs2(int x,int y)
{
queue<pair<int,int>> q;
q.push({x,y});
v2[x][y]=1;
while(q.size())
{
auto t=q.front();
q.pop();
for(int i=0;i<8;i++)
{
int xx=t.first+idx2[i],yy=t.second+idy2[i];
if(check(xx,yy)&&v2[xx][yy]==0&&a[xx][yy]==0)
{
v2[xx][yy]=1;
q.push({xx,yy});
}
if(check(xx,yy)&&v1[xx][yy]==0&&a[xx][yy]==1)
{
ans++;
bfs1(xx,yy);
}
}
}
}//枚举外海
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cin>>t;
while(t--)
{
bool flag = false;
ans=0;
memset(v1,0,sizeof v1);
memset(v2,0,sizeof v2);
memset(a,0,sizeof a);
cin>>n>>m;
for(int i = 0; i < n; i ++)
{
string s;
cin >> s;
for(int j = 0; j < m; j ++)
a[i][j] = s[j] - '0';
}
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
if(i==0||j==0){
if(a[i][j]==0&&v2[i][j]==0){//外海肯定在最外面一圈
bfs2(i,j);
flag=true;
}
}
}
if(!flag) cout<<"1"<<endl;
else
cout<<ans<<endl;
}
}