描述
小Kui喜欢把别人的名字拆开来,比如“螺”就可以拆成“虫田糸”,小Kui的语文学的不是很好,于是她决定使用编程的方式来解决这个问题。
给出一个01矩阵,1占据的部分即为需要拆的字,如果两个1分享一条边,那么它们连通。连通具有传递性,即如果a、b连通,b、c连通,则a、c连通。
连通的一系列1被看做可以拆出的一块,现在小Kui需要输出这些拆出的块(用一个01矩阵表示,并且要求矩阵的大小尽可能的小)。
为了确保输出的顺序尽可能的和书写的顺序一致,小Kui从每个块中选出最左上角的点(最左侧的点中,最靠上的)作为代表点,然后按照代表点从左到右(若相同则按从上到下)的顺序输出所有拆出的块。
输入
输入的第一行为两个正整数N、M,表示01矩阵的大小。
接下来N行,每行M个01字符,描述一个需要拆的字。
对于40%的数据,满足1<=N,M<=10。
对于100%的数据,满足1<=N,M<=500。
输出
按照代表点从左到右(若相同则按从上到下)的顺序输出所有拆出的块。
对于每个块,先输出其大小,然后用对应的01矩阵表示这个块。
额外的样例
样例输入
11 17
00000000000000000
00001111111100000
00000000000000000
00111111111111100
00000000100000000
00000010101110000
00000110100011000
00011100100001000
00000010100000000
00000001100000000
00000000000000000
样例输出
7 13
1111111111111
0000001000000
0000001000000
0000001000000
0000001000000
0000001000000
0000011000000
3 4
0001
0011
1110
1 8
11111111
1 1
1
3 4
1110
0011
0001
样例输入
14 22
0000000000001111111100
0000000000001101101100
0000110000001111111100
0000110000001101101100
0111111110001111111100
0110110110000000000000
0110110110000011000000
0111111110001111111000
0000110000000001100000
0000110110001111111100
0111111111000111111000
0000000010001101101100
0000000000000001100000
0000000000000011100000
样例输出
10 9
000110000
000110000
111111110
110110110
110110110
111111110
000110000
000110110
111111111
000000010
5 8
11111111
11011011
11111111
11011011
11111111
8 8
00110000
11111110
00011000
11111111
01111110
11011011
00011000
00111000
思路:
简单的bfs或者dfs求联通块,在dfs过程中要维护上下左右四个最值。然后记录下每个联通的1的坐标,最后输出的时候利用坐标变换把原图中的坐标映射到要输出的图中。也就是要输出的图是以left 和 up 作为新矩阵中 0,0这个点的。记录的每个联通的坐标要做 x - up, y - left 这样的变换。把1填到要输出的矩阵中行了。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 505;
int n, m;
string G[maxn];
int vis[maxn][maxn];
int up, down, Left, Right;
int dir[4][2] = {{0,1}, {1,0}, {-1,0}, {0,-1}};
bool judge(int x, int y) {
if (x >= 0 && x < n && y >= 0 && y < m && G[x][y] == '1' && !vis[x][y]) {
return true;
}
return false;
}
void dfs(int x, int y, vector<pair<int,int>>& res) {
vis[x][y] = 1;
for (int i = 0; i < 4; ++i) {
int dx = x + dir[i][0];
int dy = y + dir[i][1];
if (judge(dx, dy)) {
if (dx < up) up = dx;
if (dx > down) down = dx;
if (dy > Right) Right = dy;
if (dy < Left) Left = dy;
res.push_back(make_pair(dx,dy));
dfs(dx, dy, res);
}
}
}
void print(int x, int y, vector<pair<int,int>>&res) {
int len = Right - Left + 1;
int width = down - up + 1;
//cout << up << " " << down << " " << Left << " " << Right << endl;
int g[width][len];
for (int i = 0; i < width; ++i) {
for(int j = 0; j < len; ++j)
g[i][j] = 0;
}
cout << width << " " << len << endl;
for (int i = 0; i < (int)res.size(); ++i) {
auto now = res[i];
int dx = now.first - up;
int dy = now.second - Left;
g[dx][dy] = 1;
}
for (int i = 0; i < width; ++i) {
for (int j = 0; j < len; ++j)
cout << g[i][j];
cout << endl;
}
}
void solve() {
vector<pair<int,int>>res;
for (int j = 0; j < m; ++j) {
for(int i = 0; i < n; ++i) {
if (G[i][j] == '1' && !vis[i][j]) {
up = i;
down = i;
Left = j;
Right = j;
res.clear();
res.push_back(make_pair(i,j));
dfs(i, j, res);
print(i, j, res);
}
}
}
}
int main() {
cin >> n >> m;
for (int i = 0; i < n; ++i) {
cin >> G[i];
}
memset(vis, 0, sizeof(vis));
solve();
return 0;
}