题目所属: 隐式图的搜索
题目意思: 给定一个5 x 5 的棋盘,棋盘上面有12个黑色的棋子和12个白色的棋子和一个空格, 最开始的这些棋子的位置是不定的, 要求我们找到最小的步数去把这个棋盘转化为最后的那个样子,最后输出。
解题思路: 我们容易相到的是直接bfs去搜索求出最小步数,但是这一题也可以用dfs+回溯做。首先我们开一个Fin数组用来保存最后的位置,然后就是我们对空格周围的8个方向进行一一的深搜回溯,我们每进行一次搜索就判断是否当前以及到达最后的位置(这个通过judge函数判断),如果是那么判断能否更新ans。其中我们还可以进行优化,就是对于Tans > 10的搜索肯定都是没用的那么我们就可以直接舍去。不用去开vis数组来标记是否走过 , 我们只要限制Tans 小于11即可,如果是Tans 大于10直接return.
代码:
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#include <cstdio>
#include <stack>
#include <queue>
using namespace std;
int Fin[5][5] = {//保存最后的结果
{1, 1, 1, 1, 1},
{0, 1, 1, 1, 1},
{0, 0, -1, 1, 1},
{0, 0, 0, 0, 1},
{0, 0, 0, 0, 0},
};
int dir[8][2] = {//方向数组
{-2, -1},
{-2, 1},
{-1, 2},
{1, 2},
{2, 1},
{2, -1},
{1, -2},
{-1, -2}
};
int G[5][5]; //保存输入的位置
char ch;
int t, ans;
struct Point {//坐标结构体
int x;
int y;
};
//判断是否到最后的位置
int judge(){
for(int i = 0 ; i < 5 ; i++){
for(int j = 0 ; j < 5 ; j++){
if(G[i][j] != Fin[i][j])//只要有不像同的就return 0
return 0;
}
}
return 1;
}
//深搜回溯
void dfs(int x , int y , int Tans){//传入三个参数坐标以及步数
if(Tans > 10) return;//大于10步的都不用搜索
if(judge()){//如果这时候满足了,那么判断ans是否大于Tans
if(ans > Tans) ans = Tans;
return;
}
for (int i = 0; i < 8; i++) {//8个方向搜索
if (dir[i][0]+x < 0 || dir[i][0]+x >= 5) continue;//越界就继续下一个方向
if (dir[i][1]+y < 0 || dir[i][1]+y >= 5) continue;//越界就继续下一个方向
swap(G[x][y] , G[dir[i][0]+x][dir[i][1]+y]);//将空格位置交换
dfs(x+dir[i][0] , y+dir[i][1] , Tans+1);//递归继续搜索
swap(G[x][y] , G[dir[i][0]+x][dir[i][1]+y]);//空格从新移回
}
}
//主函数
int main() {
scanf("%d%*c", &t);
while (t--) {
Point p;
//处理输入
for(int i = 0 ; i < 5 ; i++){
for(int j = 0 ; j < 5 ; j++){
if(j == 4) scanf("%c%*c" , &ch);
if(j < 4) scanf("%c" , &ch);
if(ch == ' '){
G[i][j] = -1;
p.x = i ; p.y = j;
}
else G[i][j] = ch-'0';
}
}
ans = 999999999;
dfs(p.x , p.y , 0);
if (ans > 10) printf("Unsolvable in less than 11 move(s).\n");
else printf("Solvable in %d move(s).\n", ans);
}
return 0;
}