版权声明:本文为博主原创作品, 转载请注明出处! https://blog.csdn.net/solider98/article/details/84898227
Description
在一个5×5的棋盘上有12个白色的骑士和12个黑色的骑士, 且有一个空位。在任何时候一个骑士都能按照骑
士的走法(它可以走到和它横坐标相差为1,纵坐标相差为2或者横坐标相差为2,纵坐标相差为1的格子)移动到空
位上。 给定一个初始的棋盘,怎样才能经过移动变成如下目标棋盘: 为了体现出骑士精神,他们必须以最少的步
数完成任务。
Input
第一行有一个正整数T(T<=10),表示一共有N组数据。接下来有T个5×5的矩阵,0表示白色骑士,1表示黑色骑
士,*表示空位。两组数据之间没有空行。
Output
对于每组数据都输出一行。如果能在15步以内(包括15步)到达目标状态,则输出步数,否则输出-1。
Sample Input
2
10110
01*11
10111
01001
00000
01011
110*1
01110
01010
00100
Sample Output
7
-1
思路分析:
使用IDA*或A*均可, 估价函数为当前格局与目标格局除空格之外对应位置上元素不相同的元素的个数(为达到目标状态, 这些上的骑士必须跳到空格处), 下面给出基于此策略的AC代码, 第一个为基于IDA*的解法, 第二个为基于A*的解法
//BZOJ1085_骑士精神
#include <iostream>
#include <cstdio>
using namespace std;
const int dx[8] = {-1, -2, -2, -1, 1, 2, 2, 1};
const int dy[8] = {-2, -1, 1, 2, 2, 1, -1, -2};
const char tar[6][6] = {{'0', '0', '0', '0', '0', '0'}
, {'0', '1', '1', '1', '1', '1'}
, {'0', '0', '1', '1', '1', '1'}
, {'0', '0', '0', '*', '1', '1'}
, {'0', '0', '0', '0', '0', '1'}
, {'0', '0', '0', '0', '0', '0'}};
char G[6][7];
int maxDeep;
////返回当前局面与目标局面同一位置不同元素的个数
int F(){
int res = 0;
for(int i = 1; i <= 5; ++i)
for(int j = 1; j <= 5; ++j)
if(tar[i][j] != G[i][j] && tar[i][j] != '*') ++res;
return res;
}
//已经进行now次变换, 空格在第sx行, sy列处
bool dfs(int now, int sx, int sy){
int f = F(); if(now + f > maxDeep) return false;
if(now == maxDeep) return true;
for(int i = 0; i <= 7; ++i){
int x = sx + dx[i], y = sy + dy[i];
if(x >= 1 && x <= 5 && y >= 1 && y <= 5){
swap(G[sx][sy], G[x][y]);
if(dfs(now + 1, x, y)) return true;
swap(G[sx][sy], G[x][y]);
}
}
return false;
}
int main(){
int T; scanf("%d", &T);
while(T--){
for(int i = 1; i <= 5; ++i) scanf("%s", G[i] + 1);
int sx, sy;
for(int i = 1; i <= 5; ++i)
for(int j = 1; j <= 5; ++j)
if(G[i][j] == '*'){
sx = i, sy = j;
goto GO1;
}
GO1:
if(!F()){
cout << 0 << endl; continue;
}
maxDeep = 0; while(++maxDeep, maxDeep <= 15 && !dfs(0, sx, sy));
if(maxDeep <= 15) cout << maxDeep << endl; else cout << -1 << endl;
}
return 0;
}
//BZOJ1085_骑士精神_A_Star
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <string>
#include <cstring>
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef pair<int, int> pii;
typedef pair<pii, string> piis;
const int INF = 0x3f3f3f3f;
const int dx[8] = {-1, -2, -2, -1, 1, 2, 2, 1};
const int dy[8] = {-2, -1, 1, 2, 2, 1, -1, -2};
const char tar[6][6] = {{'0', '0', '0', '0', '0', '0'}
, {'0', '1', '1', '1', '1', '1'}
, {'0', '0', '1', '1', '1', '1'}
, {'0', '0', '0', '*', '1', '1'}
, {'0', '0', '0', '0', '0', '1'}
, {'0', '0', '0', '0', '0', '0'}};
char G[6][6];
//根据字符串str还原数组arr
void toArr(const string &str, char arr[6][6]){
for(int i = 1, k = 0; i <= 5; ++i)
for(int j = 1; j <= 5; ++j) arr[i][j] = str[k++];
}
//返回arr对应的字符串
void toStr(const char arr[6][6], string &str){
char s[26]; s[25] = '\0';
for(int i = 1, k = 0; i <= 5; ++i)
for(int j = 1; j <= 5; ++j) s[k++] = arr[i][j];
str = s;
}
//返回arr的估价函数值
int F(const char arr[6][6]){
int res = 0;
for(int i = 1; i <= 5; ++i)
for(int j = 1; j <= 5; ++j)
if(arr[i][j] != '*' && arr[i][j] != tar[i][j]) ++ res;
return res;
}
//返回arr中, 空格所在位置
void getSpace(const char arr[6][6], int &x, int &y){
for(int i = 1; i <= 5; ++i)
for(int j = 1; j <= 5; ++j)
if(arr[i][j] == '*'){
x = i, y = j; return;
}
}
int main(){
int T; scanf("%d", &T);
while(T--){
char s[7];
for(int i = 1; i <= 5; ++i)
scanf("%s", s + 1), memcpy(G[i] + 1, s + 1, sizeof(char) * 5);
//first.first:实际代价+估价函数值, first.second:实际代价, second:对应字符串
priority_queue<piis , vector<piis>, greater<piis> > pq;
string beg; toStr(G, beg);
string end; toStr(tar, end);
int res = -1;
pq.push(mp(mp(F(G), 0), beg));
while(pq.size() && pq.top().fi.fi <= 15){
int v = pq.top().fi.se; string str = pq.top().se; pq.pop();
if(str == end){
res = v; break;
}
char arr[6][6]; toArr(str, arr);
int x, y; getSpace(arr, x, y);
for(int i = 0; i <= 7; ++i){
int a = x + dx[i], b = y + dy[i];
if(a >= 1 && a <= 5 && b >= 1 && b <= 5){
swap(arr[x][y], arr[a][b]);
string ts; toStr(arr, ts);
int f = F(arr), p = v + 1 + f;
if(p <= 15 || p == 15 && ts == end)
pq.push(mp(mp(p, v + 1), ts));
swap(arr[x][y], arr[a][b]);
}
}
}
cout << res << endl;
}
return 0;
}