每日一题之 hiho232周 拆字游戏

描述
小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;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值