题目描述:
输入一个网格,某些网格的点上标有数字,表示这个点的度数,你需要在格子中填入正斜杠或者反斜杠,要求使度数与给定的度数相等,输出任意一组解即可(原题目的输入样例少输入了样例组数),下图是一个例子:
题解:
本题可以使用并查集来判环,注意使用并查集的话不能使用路径压缩,不然回溯的时候会丢失信息。
我们可以按照位置进行搜索,依次考虑当前位置填入正斜杠和反斜杠,然后判断当前的度数是否满足条件即可。
除此之外我们可以使用一些剪枝来减少搜索状态,我们需要记录当前每个点上的度数和改点最多还能增加多少度数,搜索之前需要先判断,受到影响的四个点是否能够达到输入的要求,不能的话我们直接剪枝即可。
代码:
#include <bits/stdc++.h>
const int MAXN = 7;
const int NUM_DIRECTION = 4;
using namespace std;
int T, n;
char ans[MAXN + 1][MAXN + 1], grid[MAXN + 2][MAXN + 2]; // 注意字符串末尾结束符也要占用空间
int limit[MAXN + 1][MAXN + 1], num[MAXN + 1][MAXN + 1];
int h[(MAXN + 1) * (MAXN + 1)];
int dx[] = {
0, 0, 1, 1};
int dy[] = {
0, 1, 1, 0};
int find(int x) {
return h[x] == x ? x : find(h[x]); }
bool check(int x, int y)
{
for (int i = 0; i < NUM_DIRECTION; i++) {
int nx = x + dx[i];
int ny = y + dy[i];
if (grid[nx][ny] == '.') {
continue; }
if (i == 0 && num[nx][ny] != grid[nx][ny] - '0') {
return false; }
if (num[nx][ny] <= grid[nx][ny] - '0' &&
num[nx][ny] + limit[nx][ny] >= grid[nx][ny] - '0') {
continue; }
return false;
}
return true;
}
bool dfs(int x, int y)
{
if (y == n) {
x++;
y = 0;
}
if (x == n) {
return true; }
for (int i = 0; i < NUM_DIRECTION; i++) {
limit[x + dx[i]][y + dy[i]]--; }
num[x][y]++, num[x + 1][y + 1]++;
if (check(x, y)) {
int fa = find(x * (n + 1) + y);
int fb = find((x + 1) * (n + 1) + y + 1);
if (fa != fb) {
// 没有形成环
h[fa] = fb;
ans[x][y] = '\\';
if (dfs(x, y + 1)) {
return true; }
ans[x][y] = 0;
h[fa] = fa;
}
}
num[x + 1][y + 1]--, num[x][y]--;
num[x][y + 1]++, num[x + 1][y]++;
if (check(x, y)) {
int fa = find(x * (n + 1) + y + 1);
int fb = find((x + 1) * (n + 1) + y);
if (fa != fb) {
h[fa] = fb;
ans[x][y] = '/';
if (dfs(x, y + 1)) {
return true; }
ans[x][y] = 0;
h[fa] = fa;
}
}
num[x + 1][y]--, num[x][y + 1]--;
for (int i = 0; i < NUM_DIRECTION; i++) {
limit[x + dx[i]][y + dy[i]]++; }
return false;
}
int main()
{
cin >> T;
while (T--) {
cin >> n;
memset(ans, 0, sizeof(ans));
memset(num, 0, sizeof(num));
for (int i = 0; i < (n + 1) * (n + 1); i++) {
h[i] = i;}
for (int i = 0; i < n + 1; i++) {
cin >> grid[i]; }
for (int i = 0; i < n + 1; i++) {
for (int j = 0; j < n + 1; j++) {
if ((i == 0 && j == 0) || (i == 0 && j == n) ||
(i == n && j == 0) || (i == n && j == n)) {
limit[i][j] = 1;
} else if (i == 0 || j == 0 || i == n || j == n) {
limit[i][j] = 2;
} else {
limit[i][j] = 4;
}
}
}
dfs(0, 0);
for (int i = 0; i < n; i++) {
cout << ans[i] << endl; }
}
return 0;
}