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,否则输出最小的步数 
	}
}


posted @ 2017-08-12 19:05  琳小羽  阅读(120)  评论(0编辑  收藏  举报