AcWing 4959. 岛屿个数 以及其模板题 luoguP1162填涂颜色
#include <bits/stdc++.h> //实测用万能头与直接写头文件时间没什么区别
using namespace std;
const int N = 60;
typedef pair<int, int> PII;
char ma[N][N]; //注意题目中0 1 是以字符的形式输入的 要定义成char 注意审题 不能取名map会冲突
int n, m;
int T;
int res; //定义答案 岛屿个数
int dx[4] = {1, -1, 0, 0}, dy[4] = {0, 0, 1, -1}; //岛屿坐标偏移量 四个方向
int dxx[8] = {1, -1, 0, 0, 1, 1, -1, -1}, dyy[8] = {0, 0, 1, -1, 1, -1, -1, 1}; //海水坐标偏移量 八个方向
bool st[N][N]; //判断当前点有没有被搜索过
//搜索岛屿 利用bfs板子
void bbfs(int x, int y)
{
res ++ ; //利用函数一次证明就搜到了一个全新的岛屿 计入答案
queue<PII> q;
q.push({x, y});
st[x][y] = true;
while (q.size())
{
auto t = q.front(); //取出队头
q.pop();
for (int i = 0; i < 4; i ++ )
{
int a = t.first + dx[i], b = t.second + dy[i];
if (a >= 0 && a <= n + 1 && b >= 0 && b <= m + 1 && !st[a][b] && ma[a][b] == '1') //搜下一个是陆地的点 找到这个岛屿的全部点
{
st[a][b] = true;
q.push({a, b});
}
}
}
}
//搜索海水 也利用bfs板子
void bfs(int x, int y)
{
queue<PII> q;
q.push({x, y});
st[x][y] = true; //将该点标记为搜过了
while (q.size())
{
auto t = q.front();
q.pop();
for (int i = 0; i < 8; i ++ )
{
int a = t.first + dxx[i], b = t.second + dyy[i];
if (a >= 0 && a <= n + 1 && b >= 0 && b <= m + 1 && !st[a][b]) //当前点没搜过
{
if (ma[a][b] == '1') bbfs(a, b); //去搜岛屿函数里把这个点所在的岛屿上的点全搜了 并全部标记为搜过 进入该函数一次 答案res岛屿个数就加1
else
{
st[a][b] = true; //如果该点不是岛屿 也标记为搜过
q.push({a, b}); //入队 继续搜下一个也是海水的点
}
}
}
}
}
int main()
{
scanf("%d", &T);
while ( T -- )
{
//由于有多组测试数据 每次循环开始时 把所有要用到的数组和答案岛屿个数全部清空
memset(st, 0, sizeof st);
res = 0;
memset(ma, '0' , sizeof ma);
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
cin >> ma[i][j]; //矩阵不能用scanf("%d", &ma[i][j])来读 我目前也不知道为什么!!! (可能是输入的数据之间没有空格?3.31
//注意这里有一个很巧妙的点
//我们之所以将地图从(1,1)开始存 是因为我们要在外圈扩展一圈海水
//保证我们下面从bfs(0,0)开始搜索时,不会产生(0,0)这个点就是陆地的情况导致我们无法进入bfs(),
//(bfs()搜索海水点的函数 得保证输入的这个点(x,y)本身是海水
//也不会产生点(0, 0) 被陆地包围的情况 海水无法向外扩展点读入 (如图1)
bfs(0, 0); //从海水点(0, 0)开始向外扩展搜索
printf("%d\n", res);
}
return 0;
}
我们可以发现这组数据如果不把海水向外扩展一圈 (0, 0)一开始搜索就会直接碰到全部陆地 bfs函数内队列直接清空 无法继续执行函数
模板题 填涂颜色
填涂颜色
题目描述
由数字 \(0\) 组成的方阵中,有一任意形状的由数字 \(1\) 构成的闭合圈。现要求把闭合圈内的所有空间都填写成 \(2\)。例如:\(6\times 6\) 的方阵(\(n=6\)),涂色前和涂色后的方阵如下:
如果从某个 \(0\) 出发,只向上下左右 \(4\) 个方向移动且仅经过其他 \(0\) 的情况下,无法到达方阵的边界,就认为这个 \(0\) 在闭合圈内。闭合圈不一定是环形的,可以是任意形状,但保证闭合圈内的 \(0\) 是连通的(两两之间可以相互到达)。
0 0 0 0 0 0
0 0 0 1 1 1
0 1 1 0 0 1
1 1 0 0 0 1
1 0 0 1 0 1
1 1 1 1 1 1
0 0 0 0 0 0
0 0 0 1 1 1
0 1 1 2 2 1
1 1 2 2 2 1
1 2 2 1 2 1
1 1 1 1 1 1
输入格式
每组测试数据第一行一个整数 \(n(1 \le n \le 30)\)。
接下来 \(n\) 行,由 \(0\) 和 \(1\) 组成的 \(n \times n\) 的方阵。
方阵内只有一个闭合圈,圈内至少有一个 \(0\)。
输出格式
已经填好数字 \(2\) 的完整方阵。
样例 #1
样例输入 #1
6
0 0 0 0 0 0
0 0 1 1 1 1
0 1 1 0 0 1
1 1 0 0 0 1
1 0 0 0 0 1
1 1 1 1 1 1
样例输出 #1
0 0 0 0 0 0
0 0 1 1 1 1
0 1 1 2 2 1
1 1 2 2 2 1
1 2 2 2 2 1
1 1 1 1 1 1
提示
对于 \(100\%\) 的数据,\(1 \le n \le 30\)。
#include <bits/stdc++.h>
using namespace std;
const int N = 40;
typedef pair<int, int> PII;
int ma[N][N];
int n;
int dx[4] = {1, -1, 0, 0}, dy[4] = {0, 0, 1, -1};
int dxx[8] = {1, -1, 0, 0, 1, -1, 1, -1}, dyy[8] = {0, 0, 1, -1, 1, 1, -1, -1};
bool st[N][N];
void bbfs(int x, int y)
{
queue<PII> q;
q.push({x, y});
while (q.size())
{
auto t = q.front();
q.pop();
for (int i = 0; i < 8; i ++ )
{
int a = t.first + dxx[i], b = t.second + dyy[i];
if (a >= 0 && a <= n + 1 && b >= 0; b <= n + 1 && !st[a][b] && ma[a][b] == 1)
{ //这里if底下必须要加括号把下面代码扩起来 不是说向后空四格下面两行代码就都归if管,要不然答案错误
q.push({a, b}); //一定要注意细节 不要为了代码美观丧失准确性
st[a][b] = true;
}
}
}
}
void bfs(int x, int y)
{
queue<PII> q;
q.push({x, y});
while (q.size())
{
auto t = q.front();
q.pop();
for (int i = 0; i < 4; i ++ )
{
int a = t.first + dx[i], b = t.second + dy[i];
if (a >= 0 && a <= n + 1 && b >= 0 && b <= n + 1 && !st[a][b])
{
if (ma[a][b] == 1) bbfs(a, b);
else
{
q.push({a, b});
st[a][b] = true;
}
}
}
}
}
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= n; j ++ )
scanf("%d", &ma[i][j]);
bfs(0, 0);
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= n; j ++ )
{
if (!st[i][j]) ma[i][j] = 2;
}
for (int i = 1; i <= n; i ++ )
{
for (int j = 1; j <= n; j ++ )
printf("%d ", ma[i][j]);
cout << endl;
}
return 0;
}