题意:给出了一个5×5的棋盘,任意放了12个白子,12个黑子,有一个空位,每个棋子都要像象棋里的马一样走‘日’,跳到空白位置,问是否可以在10步以内(包括十步)走成题目第一个图片中的样子,如果可以输出最小的步数,否则输出“Uns....”
题解:用bfs做的这题,主要是判重的时候,把棋盘上白子为0,黑子为1,空白为2,当成25位的3进制数字,转化成十进制用map判断是否访问过。
#include <stdio.h>
#include <string.h>
#include <queue>
#include <algorithm>
#include <cmath>
#include <map>
using namespace std;
const int N = 5;
struct ST {
int ch[N][N];
int step;
int x, y;
}s, st;
int x, y, ans;
const int dx[] = {-1, -1, 1, 1, -2, -2, 2, 2};
const int dy[] = {-2, 2, -2, 2, 1, -1, 1, -1};
int tar[N][N] = {{1, 1, 1, 1, 1}, {0, 1, 1, 1, 1}, {0, 0, 2, 1, 1}, {0, 0, 0, 0, 1}, {0, 0, 0, 0, 0}};
queue<ST> q;
map<long long, int> m;
int hash(ST temp) {
long long cnt, k;
cnt = k = 0;
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
cnt += temp.ch[i][j] * pow(3, k++);
if (!m[cnt]) {
m[cnt] = 1;
return 1;
}
return 0;
}
void bfs() {
q.push(s);
while(!q.empty()) {
st = q.front();
q.pop();
if (st.step > 9)
return;
for (int i = 0; i < 8; i++) {
int x1 = st.x + dx[i];
int y1 = st.y + dy[i];
if (x1 < 0 || x1 >= N || y1 < 0 || y1 >= N)
continue;
s = st;
s.ch[s.x][s.y] = s.ch[x1][y1];
s.ch[x1][y1] = 2;
s.x = x1;
s.y = y1;
if (hash(s)) {
s.step = st.step + 1;
if (memcmp(s.ch, tar, sizeof(tar)) == 0) {
ans = s.step;
return;
}
q.push(s);
}
}
}
}
int main() {
int t;
char c;
scanf("%d", &t);
getchar();
while (t--) {
while (!q.empty())
q.pop();
ans = -1;
m.clear();
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
scanf("%c", &c);
if (c == '0')
s.ch[i][j] = 0;
else if (c == '1')
s.ch[i][j] = 1;
else {
s.ch[i][j] = 2;
s.x = i;
s.y = j;
}
}
getchar();
}
if (memcmp(s.ch, tar, sizeof(tar)) == 0) {
printf("Solvable in 0 move(s).\n");
continue;
}
s.step = 0;
hash(s);
bfs();
if (ans != -1)
printf("Solvable in %d move(s).\n", ans);
else
printf("Unsolvable in less than 11 move(s).\n");
}
return 0;
}