题目描述
输入输出格式
输入格式:第一行有一个正整数T(T<=10),表示一共有N组数据。接下来有T个5×5的矩阵,0表示白色骑士,1表示黑色骑士,*表示空位。两组数据之间没有空行。
输出格式:
对于每组数据都输出一行。如果能在15步以内(包括15步)到达目标状态,则输出步数,否则输出-1。
输入输出样例
说明
这道题是一道很好的搜索题 结合了迭代加深搜索还有$A*$
考虑到枚举棋子走法很麻烦 并且只有一个空格 所以考虑到走空格 每次有$8$种走法 开个增量数组搞一搞就可以了
迭代加深首先肯定是枚举走的最多的次数 然而这个玩意还是要T
所以使用$A*$估价函数 怎么估呢
考虑到每次移动空格至多使一个棋子走到目标位置 所以统计有多少棋子不在正确的位置上 这就是最少步数
如果最少步数加上当前步数超界就返回
代码
#include <bits/stdc++.h> #define oo 1e9 using namespace std; int n, tag, T, x, y, s[10][10], G[10][10]; int zl[8][2] = {{-2,-1},{-1,-2},{1,-2},{2,-1},{2,1},{1,2},{-1,2},{-2,1}}; char h[10]; int g[10][10] = {{0,0,0,0,0,0}, {0,1,1,1,1,1}, {0,0,1,1,1,1}, {0,0,0,2,1,1}, {0,0,0,0,0,1}, {0,0,0,0,0,0} }; void init( ) { for(int i = 1;i <= 5;i ++) { for(int j = 1;j <= 5;j ++) s[i][j] = G[i][j]; } } bool check( ) { for(int i = 1;i <= 5;i ++) for(int j = 1;j <= 5;j ++) { if(i == j) { if(i <= 2) if(s[i][j] != 1) return false; if(i == 3) if(s[i][j] != 2) return false; if(i >= 4) if(s[i][j] != 0) return false; } if(i < j && s[i][j] != 1) return false; if(i > j && s[i][j] != 0) return false; } return true; } int eval( ) { int cnt = 0; for(int i = 1;i <= 5;i ++) for(int j = 1;j <= 5;j ++) { if(s[i][j] != g[i][j] && s[i][j] != 2) cnt ++; } return cnt; } void dfs(int step, int lim, int x, int y) { if(step == lim) { if(check( )) tag = min(tag, step); return ; } int res = eval( ); if(step + res > lim) return ; if(check( )) {tag = min(tag, step); return ;} for(int i = 0;i < 8;i ++) { int xx = x + zl[i][0], yy = y + zl[i][1]; if(xx > 5 || xx < 1 || yy < 1 || yy > 5) continue; swap(s[x][y], s[xx][yy]); dfs(step + 1, lim, xx, yy); swap(s[x][y], s[xx][yy]); } } void Solve( ) { scanf("%d",& T); while(T --) { for(int i = 1;i <= 5;i ++) { scanf("%s",h + 1); for(int j = 1;j <= 5;j ++) { if(h[j] == '0') G[i][j] = 0; else if(h[j] == '1') G[i][j] = 1; else { G[i][j] = 2; x = i, y = j; } } } tag = oo; init( ); for(int i = 0;i <= 15;i ++) { //init( ); dfs(0, i, x, y); if(tag != oo) { printf("%d ", i); break; } } if(tag == oo) printf("-1 "); } } int main( ) { Solve( ); }