\(O(n^3)\) 處理 \(n\times n\) 數字華容道還原(可能無解)。
具體實現看程式碼:
solve.cpp
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
const int N = 201;
int n, l, r, L, R;
bool type;
vector<vector<int>> a, res;
vector<pair<int, int>> ans;
int fx[4] = {1, 0, -1, 0};
int fy[4] = {0, 1, 0, -1};
pair<int, int> pos[N * N];
// U L D R
inline void putans(int c) {
if (c >= 4) c -= 4;
int x = pos[0].fi + fx[c];
int y = pos[0].se + fy[c];
ans.emplace_back(x, y);
}
void Move(int val, int tx, int ty) {
auto &[x, y] = pos[val];
if (x == tx && y == ty)
return ;
if (val == 0) { // 移動的是 0 那麼固定移動直線
while (x < tx) {
int v = a[x + 1][y];
putans(0 + type);
swap(a[x + 1][y], a[x][y]);
swap(pos[v], pos[0]);
}
while (x > tx) {
int v = a[x - 1][y];
putans(2 + type);
swap(a[x - 1][y], a[x][y]);
swap(pos[v], pos[0]);
}
while (y < ty) {
int v = a[x][y + 1];
putans(1 + type);
swap(a[x][y + 1], a[x][y]);
swap(pos[v], pos[0]);
}
while (y > ty) {
int v = a[x][y - 1];
putans(3 + type);
swap(a[x][y - 1], a[x][y]);
swap(pos[v], pos[0]);
}
} else {
auto &[zx, zy] = pos[0];
if (tx != l && zx == l) { // 特判第二行的點
if (zy == y && zx + 1 == x) {
if (y < R - 1) Move(0, zx, y + 1);
else Move(0, zx, y - 1);
}
Move(0, zx + 1, zy);
}
while (y < ty) {
if (zx == l) Move(0, zx + 1, zy);
if (zx == x && zy < y) {
if (zx == r - 1) Move(0, zx - 1, zy);
else Move(0, zx + 1, zy);
}
Move(0, zx, y + 1);
Move(0, x, y + 1);
Move(0, x, y);
}
while (y > ty) {
if (zx == x && zy > y) {
if (zx == r - 1) Move(0, zx - 1, zy);
else Move(0, zx + 1, zy);
}
Move(0, zx, y - 1);
Move(0, x, y - 1);
Move(0, x, y);
}
while (x > tx) {
if (zy == y && zx < x) {
Move(0, x - 1, y);
} else {
if (zy <= y && x != r - 1) {
Move(0, x + 1, zy);
Move(0, x + 1, y + 1);
}
Move(0, x - 1, zy);
Move(0, x - 1, y);
}
Move(0, x, y);
}
}
}
void solve() {
if (r - l <= 3 && R - L <= 3) {
static vector<vector<int>> tmp(3, vector<int>(3));
vector<int> stk, st;
for (int i = l; i < r; i++) {
for (int j = L; j < R; j++) {
tmp[i - l][j - L] = a[i][j];
st.push_back(a[i][j]);
}
}
int x = pos[0].fi - l, y = pos[0].se - L;
map<int, int> pre;
sort(st.begin(), st.end());
auto key = [&](const vector<vector<int>> ve) {
int res = 0;
for (auto vv : ve)
for (auto x : vv)
res = res * 10 + lower_bound(st.begin(), st.end(), x) - st.begin();
return res;
};
queue<pair<vector<vector<int>>, pair<int, int>>> q;
q.push({tmp, {x, y}});
pre[key(tmp)] = -1;
while (!q.empty()) {
auto [u, tt] = q.front();
auto [x, y] = tt;
q.pop();
bool ok = true;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (u[i][j] != res[i + l][j + L]) {
ok = false;
break;
}
}
}
if (ok) {
while (pre[key(u)] != -1) {
int i = pre[key(u)];
stk.push_back(i);
int xx = x - fx[i];
int yy = y - fy[i];
swap(u[xx][yy], u[x][y]);
x = xx, y = yy;
}
reverse(stk.begin(), stk.end());
for (auto x : stk) {
putans(x);
}
puts("Find the solution:");
printf("The solution steps is: %d\n", (int)ans.size());
int idx = 0;
for (auto [x, y] : ans) {
++idx;
printf("The %d : (%d %d)\n", idx, x, y);
}
return ;
}
for (int i = 0; i < 4; i++) {
int xx = x + fx[i];
int yy = y + fy[i];
if (xx >= 0 && xx < 3 && yy >= 0 && yy < 3) {
swap(u[x][y], u[xx][yy]);
swap(x, xx);
swap(y, yy);
int kk = key(u);
if (!pre.count(kk)) {
pre[kk] = i;
q.push({u, {x, y}});
}
swap(x, xx);
swap(y, yy);
swap(u[x][y], u[xx][yy]);
}
}
}
puts("No solution!");
return ;
}
if (r - l <= 3) {
auto _a = a, _res = res;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
a[j][n - i - 1] = _a[i][j];
res[j][n - i - 1] = _res[i][j];
}
}
for (int v = 0; v < n * n; v++) {
swap(pos[v].fi, pos[v].se);
pos[v].se = n - pos[v].se - 1;
}
swap(l, L);
swap(r, R);
swap(L, R);
L = n - L, R = n - R;
type = !type;
return solve();
}
bool ok = true;
for (int i = L; i < R; i++) {
ok &= a[l][i] == res[l][i];
}
if (!ok) {
Move(res[l][L + 1], l, L);
if (pos[res[l][L]].fi == l) {
Move(0, l + 1, pos[0].se);
Move(0, l + 1, pos[res[l][L]].se);
Move(0, l, pos[0].se);
if (pos[0].se + 1 < R)
Move(0, l, pos[0].se + 1);
else
Move(0, l, pos[0].se - 1);
Move(0, l + 1, pos[0].se);
}
Move(res[l][L], l + 1, L);
for (int j = L + 1; j < R - 1; j++) {
Move(res[l][j + 1], l, j);
}
Move(0, pos[0].fi, R - 1);
Move(0, l, R - 1);
Move(0, l, L);
Move(0, l + 1, L);
}
l++;
solve();
}
int main() {
scanf("%d", &n);
a.resize(n, vector<int>(n));
res.resize(n, vector<int>(n));
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
scanf("%d", &a[i][j]);
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (i < n - 1 || j < n - 1) res[i][j] = i * n + j + 1;
pos[a[i][j]].fi = i;
pos[a[i][j]].se = j;
}
}
l = L = 0, r = R = n;
solve();
return 0;
}