博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
骑士精神
阅读量:4561 次
发布时间:2019-06-08

本文共 4247 字,大约阅读时间需要 14 分钟。

【题目描述】

在一个5×5的棋盘上有12个白色的骑士和12个黑色的骑士, 且有一个空位。在任何时候一个骑士都能按照骑士的走法(它可以走到和它横坐标相差为1,纵坐标相差为2或者横坐标相差为2,纵坐标相差为1的格子)移动到空位上。

给定一个初始的棋盘,怎样才能经过移动变成如下目标棋盘:

为了体现出骑士精神,他们必须以最少的步数完成任务。

【输入描述】

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

【输出描述】

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

【样例输入】

2

10110

01*11

10111

01001

00000

01011

110*1

01110

01010

00100

【样例输出】

7

-1

 

IDA*算法:

源代码:#include
#include
//包括【swap()】函数。using namespace std;int n,K;int ans[5][5]={
{
1,1,1,1,1}, {
0,1,1,1,1}, {
0,0,2,1,1}, {
0,0,0,0,1}, {
0,0,0,0,0}}; //目标。int x[8]={
1,1,-1,-1,2,2,-2,-2};int y[8]={
2,-2,2,-2,1,-1,1,-1}; //偷懒。bool Flag=0;int Judge(int i[5][5]) //检测判断。{ for (int a=0;a<5;a++) for (int b=0;b<5;b++) if (ans[a][b]!=i[a][b]) return 0; return 1;}int Eva(int i[5][5],int s) //相当于一个估价函数,最少(一般不可能实现)的步数都无法满足,自然不成立。{ int v=0; for (int a=0;a<5;a++) for (int b=0;b<5;b++) if (i[a][b]!=ans[a][b]) { v++; if (v+s>K) return 0; } return 1;}void Search(int s,int i[5][5],int X,int Y){ if (s==K) //已到达约定的步数。 { if (Judge(i)) Flag=1; return; } if (Flag) //更快地跳出。 return; for (int a=0;a<8;a++) { int NowX=X+x[a],NowY=Y+y[a]; //移动。 if (NowX<0||NowX>4||NowY<0||NowY>4) //不符实际。 continue; swap(i[X][Y],i[NowX][NowY]); //交换数值。 if (Eva(i,s)) //估计还有没有继续下去的意义。 Search(s+1,i,NowX,NowY); swap(i[X][Y],i[NowX][NowY]); //不行就回溯回来。 }} int main(){ scanf("%d",&n); while (n--) { int i[5][5]; //i[]表示当前所示位置的骑士。 int X,Y; //开始时的空格位置。 for (int a=0;a<5;a++) { char T[5]; scanf("%s",T); for (int b=0;b<5;b++) { if(T[b]=='*') { i[a][b]=2; X=a; Y=b; } else i[a][b]=T[b]-'0'; //0白1黑。 } } for (K=1;K<=15;K++) //迭代约定的步数。 { Search(0,i,X,Y); if (Flag) //完成目标棋局。 { printf("%d\n",K); break; } } if (!Flag) printf("-1\n"); else Flag=0; } return 0;}

 

优化剪枝:

源代码:#include
#include
using namespace std;int Goal[6][6]={
{
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}};int x[8]={
1,1,-1,-1,2,2,-2,-2};int y[8]={
2,-2,2,-2,1,-1,1,-1};int i[6][6],num[6][6],ans;int Check() //检测。{ int Num=0; for (int a=1;a<=5;a++) for (int b=1;b<=5;b++) if (i[a][b]!=Goal[a][b]) Num++; return Num;}void DFS(int xxx,int yyy,int X,int Y,int s,int limit) //其实当前所用步数为(s-1)步,[xxx,yyy]表示上个节点,[X,Y]表示此节点。{ int t=Check(); if (!t) { ans=min(ans,s-1); return; } if (s+t-2>limit) //最小(一般不可能)估价。 return; if (s>limit) return; for (int a=0;a<8;a++) { int t1=X+x[a]; int t2=Y+y[a]; if (t1>=1&&t1<=5&&t2>=1&&t2<=5&&!(t1==xxx&&t2==yyy)) //避免重复,刚交换的点不能再复回。 { swap(i[X][Y],i[t1][t2]); DFS(X,Y,t1,t2,s+1,limit); swap(i[X][Y],i[t1][t2]); } }}void Init(){ int X,Y; ans=16; for (int a=1;a<=5;a++) for (int b=1;b<=5;b++) { char t; cin>>t; if (t=='*') { i[a][b]=2; X=a; Y=b; } else i[a][b]=t-'0'; } for (int K=1;K<=15;K++) //约定。 { DFS(X,Y,X,Y,1,K); if (ans<16) //OK就打断。 { printf("%d\n",ans); return; } } printf("-1\n");}int main(){ int n; scanf("%d",&n); while (n--) Init(); return 0;}/* 思想整理: ①从小到大约定步数; ②估价后再移动搜索; ③搜索中加检验判断; ④有解就跳出并输出。 第二个代码省时的诀窍我觉得是加了节点交换的判重,但依然感觉并不是那么高效。*/

 

转载于:https://www.cnblogs.com/Ackermann/p/5573293.html

你可能感兴趣的文章
jq 删除数组中的元素
查看>>
添加按键事件处理及事件处理的参数传递
查看>>
js URL中文传参乱码
查看>>
Leetcode 367. Valid Perfect Square
查看>>
UVALive 3635 Pie(二分法)
查看>>
win系统查看自己电脑IP
查看>>
Backup&recovery备份和还原 mysql
查看>>
全局变量、局部变量、静态全局变量、静态局部变量的区别
查看>>
一道面试题及扩展
查看>>
Unity 3D 我来了
查看>>
php功能模块学习笔记
查看>>
c++实现医院检验科排班程序
查看>>
setup elk with docker-compose
查看>>
13.递归第一次
查看>>
PHP内置函数file_put_content(),将数据写入文件,使用FILE_APPEND 参数进行内容追加...
查看>>
20140316 曼联VS利物浦,罗杰斯的小九九,当4312对上4231
查看>>
mysql-索引、导入、导出、备份、恢复
查看>>
JSON.parse
查看>>
从移动优先到离线优先(一)
查看>>
数组之求子数组的最大乘积
查看>>