题目链接:https://www.luogu.org/problemnew/show/P1162
题目描述
由数字 0 组成的方阵中,有一任意形状闭合圈,闭合圈由数字 1 构成,围圈时只走上下左右 4 个方向。现要求把闭合圈内的所有空间都填写成 2 .例如: 6 ×6 的方阵( n=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
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
输入格式:
每组测试数据第一行一个整数n(1≤n≤30)
接下来 n 行,由 0 和 1 组成的n×n 的方阵。
方阵内只有一个闭合圈,圈内至少有一个 0 。
输出格式:
已经填好数字 2 的完整方阵。
输入样例#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≤n≤30
解题分析:
题目要求我们找出图中唯一的由0组成的闭合圈,然后将这个闭合圈中的所有0全部置为2,输出。注意,要将这里的闭合圈和联通块区分,因为这里不仅仅是要求是0的联通块,并且这个联通块的周围必须是由1全包围。
解题的突破口就是要发现,如果某一由0组成的联通块有在边界上的0,那么该连通块必然不可能是闭合圈(因为该0已是边界,不可能被1全包围),所以我们对每一个边界上的0进行深搜,将由他们延伸出来的连通块
全部标记,最后,图中没有标记的0必然属于闭合(因为闭合圈只有一个)。
#include <iostream> #include <cstdio> using namespace std; int map[35][35]; int vis[35][35]; int n; int dir[][2] = {1,0,0,1,-1,0,0,-1}; void dfs(int x, int y) { vis[x][y] = 1; for (int k = 0; k < 4; k++) { int xx = x + dir[k][0]; int yy = y + dir[k][1]; if (xx<1 || xx>n || yy<1|| yy>n || vis[xx][yy] || map[xx][yy] == 1)continue; //如果不符合条件,则跳过 dfs(xx, yy); } } int main() { cin >> n; for (int i = 1; i <=n; i++) for (int j = 1; j <= n; j++) scanf("%d", &map[i][j]); for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { if ((i == 1 || j == 1||i==n||j==n) && map[i][j] == 0) //对边界上的0进行深搜 { dfs(i, j); //因为由这些边界上的0延伸出来的0不可能属于闭合圈,所以将它们标记 } } } for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { if (map[i][j] == 0 && !vis[i][j])map[i][j] = 2; printf("%d ", map[i][j]); } cout << endl; } return 0; }
2018-05-30