洛谷 P2324 [SCOI2005] 骑士精神-提高+/省选-
题目描述
输入格式
第一行有一个正整数 TTT(T≤10T \le 10T≤10),表示一共有 TTT 组数据。
接下来有 TTT 个 5×55 \times 55×5 的矩阵,0
表示白色骑士,1
表示黑色骑士,*
表示空位。两组数据之间没有空行。
输出格式
对于每组数据都输出一行。如果能在 151515 步以内(包括 151515 步)到达目标状态,则输出步数,否则输出 -1
。
输入输出样例 #1
输入 #1
2
10110
01*11
10111
01001
00000
01011
110*1
01110
01010
00100
输出 #1
7
-1
说明/提示
solution
- 1 状态压缩
用低 5 位(0-4)表示空格的位置 (0 - 24)即 (00000->11000)
用 5 - 29 位表示马的颜色 0 白 1 黑 (空格不管它,默认为0) - 2 状态切换
找到空格的位置,切换空格和其中一个马(坐标相差为 1, 2的位置)的位置,修改空格坐标 - 3 双向搜索各 8 步
代码
#include "cstring"
#include "string"
#include "algorithm"
#include "iostream"
#include "vector"
#include "unordered_set"
#include "unordered_map"using namespace std;int src, dest, offset;
unordered_set<int> set, set2;
bool first;/** 1 状态压缩* 用低 5 位(0-4)表示空格的位置 (0 - 24)即 (00000->11000)* 用 5 - 29 位表示马的颜色 0 白 1 黑 (空格不管它,默认为0)* 2 状态切换* 找到空格的位置,切换空格和其中一个马(坐标相差为 1, 2的位置)的位置,修改空格坐标* 3 双向搜索各 8 步**/void print(int x) {int pos = x & 31;for (int j = 0; j < 25; j++) {if (j % 5 == 0) cout << '\n';if (j == pos) {cout << '*';continue;}cout << ((x >> (j + 5)) & 1);}
}bool ok(int v) {if (first) return v == dest;return set.count(v);
}void check(vector<int> &q, int v) {if (first) {if (!set.count(v)) {set.insert(v);q.push_back(v);}} else {if (!set2.count(v)) {set2.insert(v);q.push_back(v);}}
}bool search() {vector<int> q[2];q[0].push_back(src);for (int i = 0; i < 8; i++) {for (int u: q[i & 1]) {int pos = u & 31;for (int j = 0; j < 25; j++) {if (j == pos) continue;int r = j / 5, c = j % 5, rr = pos / 5, cc = pos % 5;if (abs((r - rr) * (c - cc)) != 2) continue;// 将第 j 匹马移动到 pos 上int bit_j = (u >> (j + 5)) & 1; // j-th 马的颜色int v = u | (bit_j << (pos + 5)); // 移动到 pos 的地方// 修改 posv = v & ~31 | j;v &= ~(1 << (j + 5)); //相应的位置 置0if (ok(v)) { // 目标int ans = i + 1 + offset;if(ans == 16) cout << -1 << endl;else cout << ans << endl;return true;}check(q[i + 1 & 1], v);}}q[i & 1].clear();}offset = 8;return false;
}int main() {int T;cin >> T;while (T--) {src = 0;for (int i = 0; i < 25; i++) {char c;cin >> c;if (c == '*') {src |= i;c = '0';}src |= (c - '0') << (i + 5);}// 11111 01111 00011 00001 00000dest = 0b000001000011000111101111101100;if (dest == src) {cout << 0 << endl;continue;}set.clear();set2.clear();first = true;offset = 0;bool flag = search();if (flag) continue;first = false;src = dest;if (!search())cout << -1 << endl;}return 0;
}