厦门理工学院OJ 1187.骑士精神 (dfs+剪枝)

Description

像骑士的忠贞
不畏惧邪恶的眼神
这过程一直放在我心底就像
挡在你胸前的盔甲
保护着我让我心疼
骑士们发挥出你们的精神
就这样强悍的骑士撑到最后
骄傲的公主的要回家整装再出发。

在这里插入图片描述
这是蔡依林的歌曲骑士精神,听歌归听歌,题还是得做。题目要求在一个5×5的棋盘上放12个白色的骑士和12个黑色的骑士, 且有一个空位。在任何时候一个骑士都能按照骑士的走法(它可以走到和它横坐标相差为1,纵坐标相差为2或者横坐标相差为2,纵坐标相差为1的格子)移动到空位上。 给定一个初始的棋盘,怎样才能经过移动变成如下目标棋盘: 为了体现出骑士精神,他们必须以最少的步数完成任务。

Input

第一行有一个正整数T(T <= 10) 表示一共有T组数据 接下来有T个5*5的矩形。0表示白色骑士1表示黑色骑士,*表示空位。(每组数据间有空行)

Output

对每组数据都输出一行。如果能在10步以内(包括10)到达目标状态,则输出步数,否则输出-1。

Sample Input

2
10110
01*11
10111
01001
00000

01011
110*1
01110
01010
00100

Sample Output

7
-1

题解

直接搜索所有可能的局面,并使用估计函数剪枝即可。在估计函数中,每次遍历统计当前局面与目标局面不同棋子的个数,考虑一步可以交换两个棋子的位置,将不同棋子的个数除以2,即可以得出当前局面到目标局面的最优情况还需几步。若最优步数+当前搜索深度>10,则该局面必定不能到达目标局面,就可以剪枝。
此外,若当前深度大于等于之前已经搜索出的解,也可剪枝。

代码

#include<iostream>
#include<queue>
#define ll long long
using namespace std;

char v[5][5];

const char a[5][5]={
'1','1','1','1','1',
'0','1','1','1','1',
'0','0','*','1','1',
'0','0','0','0','1',
'0','0','0','0','0'
};

const int nextx[8]={-2,-1,1,2,2,1,-1,-2};
const int nexty[8]={1,2,2,1,-1,-2,-2,-1};

int ans=-1;

int dis(){
	int disCnt=0;
	for(int i=0;i<5;i++){
		for(int j=0;j<5;j++){
			if(a[i][j]!=v[i][j]){
				disCnt++;
			}
		}
	}
	return disCnt/2;
}

void dfs(int cnt,int x,int y){
	if(cnt>10){
		return;
	}
	if(ans!=-1&&cnt>=ans){
		return;
	}
	int maxStep=dis(); 
	if(maxStep==0){
		if(ans==-1){
			ans=cnt;
		}
		else{
			ans=min(ans,cnt);
		}
		return;
	}
	if(cnt+maxStep>10){
		return;
	}
	for(int i=0;i<8;++i){
		int tx=x+nextx[i];
		int ty=y+nexty[i];
		if(tx<0||tx>=5||ty<0||ty>=5){
			continue;
		}
		swap(v[x][y],v[tx][ty]);
		dfs(cnt+1,tx,ty);
		swap(v[tx][ty],v[x][y]);
	}
	return;
}

int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	int t;
	cin>>t;
	while(t--){
		ans=-1;
		int x,y;
		for(int i=0;i<5;++i){
			for(int j=0;j<5;j++){
				cin>>v[i][j];
				if(v[i][j]=='*'){
					x=i;
					y=j;
				}
			}
		} 
		dfs(0,x,y); 
		cout<<ans<<endl;	
	}  
	return 0;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值