BZOJ1085 SCOI2005 骑士精神
(〃'▽'〃)φ(>ω<*) ( ̄▽ ̄)~*
最近学习搜索,看到这题就懵逼。网上就是各种A*搜索原理照着百度抄一遍贴一个代码,特别反感。
什么启发式搜索什么的看了一堆概念也没明白,其实就是深度优先搜索加剪枝吗,说多辣么神 ̄へ ̄;
1,要想知道最小步数,就得dfs枚举,但普通的dfs去漫无目的搜程序肯定会超时;
2,明确一个剪枝策略,如果棋盘上有两个位置不符合条件至少需要一步,推广为当前棋盘上有n个位置不符合题意,
则至少需要n-1步,如果当期走的步数加上至少要走的步数大于了限制,那么这条路径一定不可行;
下面在代码中来进行分析:
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
int ans; //最终答案
char map[5][5];
char lin[5][6]={"11111","01111","00*11","00001","00000"};// 用于对比的棋盘
int X[8]={1,1,-1,-1,2,2,-2,-2};
int Y[8]={2,-2,2,-2,1,-1,1,-1}; //X,Y数组用于for循环中模拟骑士的走位
int check(){ //用于判断当前棋盘是否满足题意
for(int q=0;q<5;q++){
for(int w=0;w<5;w++){
if(map[q][w]!=lin[q][w])return 0;
}
}
return 1;
}
int found(int step){
for(int q=0;q<5;q++){
for(int w=0;w<5;w++){
if(map[q][w]!=lin[q][w])step++;
}
}
return step;
}
void dfs(int step){ //step 步数
if(check()==1)ans=min(ans,step-1); //如果符合题意,取ans和step-1中较小的(step为什么要减一呢?因为是从step1开始的)
if(step>=ans)return; //超过步数限制,返回
int x,y; //前 * 所处的位置
for(int q=0;q<5;q++){
for(int w=0;w<5;w++)if(map[q][w]=='*')x=q,y=w; //找到当前 * 所处的位置
}
for(int q=0;q<8;q++){ //for循环中模拟骑士的走位
int l1=x+X[q],l2=y+Y[q]; //l1,l2为下一步的x和y
if(l1<0||l1>4||l2<0||l2>4)continue;//如果在棋盘外就跳过
swap(map[x][y],map[l1][l2]);//交换空位与骑士
if(found(step)<=ans)dfs(step+1); //如果当前的步数+当前到完成题意至少需要的步数小于限制就继续走
swap(map[x][y],map[l1][l2]);//交换回来
}
}
int main(){
int t;
cin>>t;
while(t--){
ans=16; //初始化ans为16
for(int q=0;q<5;q++){
for(int w=0;w<5;w++)cin>>map[q][w];
}
dfs(1);
cout<<(ans==16?-1:ans)<<endl; //ans等于说明走了15步以上输出-1,否则输出最小的步数
}
}