骑士精神

来源:互联网 发布:手机定位考勤软件 编辑:程序博客网 时间:2024/04/28 01:15

【题目描述】

在一个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<cstdio>#include<iostream> //包括【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<cstdio>#include<iostream>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;}/*    思想整理:        ①从小到大约定步数;        ②估价后再移动搜索;        ③搜索中加检验判断;        ④有解就跳出并输出。    第二个代码省时的诀窍我觉得是加了节点交换的判重,但依然感觉并不是那么高效。*/

 

0 0
原创粉丝点击