题意
给你一个n*m的网格,其中有些是空的,有些已经被填满了,现在要求你用1*2的砖瓦来填补这个网格——但是当网格的填补方案不唯一或不存在时,只需输出“Not unique"。
思路
首先明确概念:度 = 出度 + 入度,在本题中可以理解为上下左右四个方块中未被填满的个数。
容易发现,当填补的过程中发现一个空方块四周都是被填满的方块时——也即出现了度为0的点时,该方案不成立;而当一个方块的度为1时对于该方块的填补方案唯一。
所以我们只需要一直将度为1的方块进行处理,填补,如果无法找到这样的方块且还没填满则说明网格方案不唯一或不存在。每次处理完后该方块周围的4个方块的度会被刷新,此时再在里面找度为1的方块即可,这里可以用栈来实现;同时,为了防止一个大网格被分割为多个连通块的情况,最好遍历一遍,遍历的过程中执行处理,这样时间复杂度比每次处理后遍历低很多!
而瓦片的形状就直接定义一个常量数组,根据方向来调用。
剩下的就交给代码吧~
代码
#include <iostream>
#include <stack>
using namespace std;
string s[2023];
int n, m;
stack<pair<int, int> > sa;
const int vx[4] = {1, -1, 0, 0};
const int vy[4] = {0, 0, 1, -1};
const char bule[4] = {'v', '^', '>', '<'};
//查询该点度值
int find_d(int sx, int sy) {
int d = 0;
for (int i = 0; i < 4; ++i) {
int fx = sx + vx[i];
int fy = sy + vy[i];
if (fx >= 0 && fy >= 0 && fx < n && fy < m && s[fx][fy] == '.')
d++;
}
return d;
}
int main() {
cin >> n >> m;
for (int i = 0; i < n; ++i) {
cin >> s[i];
}
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (s[i][j] != '.')
continue;
int dd = find_d(i, j);
if (dd == 0) { //该点度数为0,说明四周都是墙,寄!
cout << "Not unique";
return 0;
}
if (dd == 1) { //该点度数为1,说明它必须找个点相连!
sa.push(make_pair(i, j)); //把该点压进去
}
}
}
while (!sa.empty()) {
int x = sa.top().first;
int y = sa.top().second;
sa.pop();
for (int i = 0; i < 4; ++i) {
int fx = x + vx[i];
int fy = y + vy[i];
if (fx >= 0 && fy >= 0 && fx < n && fy < m && s[fx][fy] == '.') {
s[x][y] = bule[(i ^ 1)];
s[fx][fy] = bule[i];
for (int j = 0; j < 4; ++j) {
int ax = fx + vx[j];
int ay = fy + vy[j];
if (ax >= 0 && ay >= 0 && ax < n && ay < m && s[ax][ay] == '.' &&
find_d(ax, ay) == 1) {
sa.push(make_pair(ax, ay));
}
}
break;
}
}
}
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (s[i][j] == '.') {
cout << "Not unique";
return 0;
}
}
}
for (int i = 0; i < n; ++i) {
cout << s[i] << '\n';
}
return 0;
}