L2-048 寻宝图
分数 25
全屏浏览题目
切换布局
作者 陈越
单位 浙江大学
给定一幅地图,其中有水域,有陆地。被水域完全环绕的陆地是岛屿。有些岛屿上埋藏有宝藏,这些有宝藏的点也被标记出来了。本题就请你统计一下,给定的地图上一共有多少岛屿,其中有多少是有宝藏的岛屿。
输入格式:
输入第一行给出 2 个正整数 N 和 M(1<N×M≤105),是地图的尺寸,表示地图由 N 行 M 列格子构成。随后 N 行,每行给出 M 位个位数,其中
0
表示水域,1
表示陆地,2
-9
表示宝藏。
注意:两个格子共享一条边时,才是“相邻”的。宝藏都埋在陆地上。默认地图外围全是水域。输出格式:
在一行中输出 2 个整数,分别是岛屿的总数量和有宝藏的岛屿的数量。
输入样例:
10 11 01000000151 11000000111 00110000811 00110100010 00000000000 00000111000 00114111000 00110010000 00019000010 00120000001
输出样例:
7 2
代码长度限制
16 KB
Java (javac)
时间限制
800 ms
内存限制
512 MB
其他编译器
时间限制
400 ms
内存限制
64 MB
解题思路:
原本在BFS里是先标记已走再进入四个方向搜索,以为能实时标记,其实并不能,因为只标记一个中心,而每次大循环都是一个中心,导致四个方向延时标记,一样会重复搜寻,导致最后一个测试超时,改为先进入方向搜索再标记,这样在没有进入队列之前就已经把四个方向该被标记的都标记了就能实时标记,搜索次数或者说入队数就能真正减少很多。然而还是有个问题就是本来是搜索上下左右四个方向,改为五个方向(包括本身就对了),废话啊,中心你不标记也要标记走过啊,恼,还是睡觉起来才想到,总的来说就是如果想标记后再搜索就四个方向然后改合适的方式,如果想先先搜索再标记,不要忘记标记中心处(也就是五个方向)。
#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
const int INF = 1e5+10;
const int dx[]={0,1,-1,0, 0};
const int dy[]={-1,0,0,1, 0};
map<pii,int> mp;
int n,m;
int bfs(int x,int y)
{
queue<pii> q;
q.push({x,y});
int have = 0;
while(q.size())
{
int hang = q.front().first;
int lie = q.front().second;
q.pop();
for(int k=0;k<5;k++)
{
int i = hang+dx[k];
int j = lie+dy[k];
if(i>=0&&i<n&&j>=0&&j<m&&mp[{i,j}]!=0)
{
if(mp[{i,j}]!=1) have = 1;
mp[{i,j}] = 0;
q.push({i,j});
}
}
}
return have;
}
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
char ch;
cin>>ch;
int val = ch-'0';
mp[{i,j}] = val;
}
}
int cnt = 0,bao = 0;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(mp[{i,j}]==0) continue;
else if(mp[{i,j}]!=0)
{
cnt++;
if(bfs(i,j)==1) bao++;
}
}
}
cout<<cnt<<" "<<bao;
return 0;
}