耗時一天,逆天數字華容道程式碼

weirdoX發表於2024-08-22

\(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;
}

相關文章