2449 骑士精神

2449 骑士精神

 

2005年省队选拔赛四川

 时间限制: 1 s
 空间限制: 128000 KB
 题目等级 : 大师 Master
 
 
 
题目描述 Description

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

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

                         

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

输入描述 Input Description

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

输出描述 Output Description

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

样例输入 Sample Input
2
10110
01*11
10111
01001
00000
01011
110*1
01110
01010
00100
样例输出 Sample Output

7

-1

数据范围及提示 Data Size & Hint

见题面

分类标签 Tags 点此展开 

 
 
解题思路:骑士的跳动实质上是空格的跳动,搜索同时判断是否与目标状态一致,记录一下步数。
 
IDA*
时间:玄学
#include<iostream>
using namespace std;
const char goal[5][6]={{"11111"},{"01111"},{"00*11"},{"00001"},{"00000"}};
const int dx[]={1,2,2,1,-1,-2,-2,-1};
const int dy[]={2,1,-1,-2,-2,-1,1,2};
char s[5][6];int T,ans;bool flag;
inline int deal(){//估价函数(A*的标志) 
    int res=0;
    for(int i=0;i<5;i++)
        for(int j=0;j<5;j++)
            if(s[i][j]!=goal[i][j]) res++;
    return res;
}
void dfs(int now,int x,int y,int limit){
    int c=deal();
    if(now==limit){if(!c) ans=limit,flag=1;return ;}//同层的ans是一样的 
    if(now-1+c>limit) return ;//c个不同的至少需要c-1操作,超过限制,剪枝 
    for(int i=0;i<8;i++){
        int nx=x+dx[i],ny=y+dy[i];
        if(nx>=0&&nx<5&&ny>=0&&ny<5){
            swap(s[x][y],s[nx][ny]);
            if(flag) return ;//已有答案,迅速跳出 
            dfs(now+1,nx,ny,limit);
            swap(s[x][y],s[nx][ny]);
        }
    }
}
int main(){
    cin>>T;
    while(T--){
        int x,y;
        ans=16;
        for(int i=0;i<5;i++)
            for(int j=0;j<5;j++){
                cin>>s[i][j];
                if(s[i][j]=='*') x=i,y=j;//空格点 
            }
        for(int k=0;k<=15;k++){//枚举限制层数 
            flag=0;ans=16;
            dfs(0,x,y,k);
            if(ans==k)break;//前面有答案,后面就不更新了 
        }
        cout<<(ans==16?-1:ans)<<endl;//判一下是否超过15步 
    }
    return 0;
}

 

A*算法

时间:玄学

#include<iostream>//朴素A*,没有上面的剪枝部分,当然跑的不如上面的快,但是便于理解 
#include<cstring>
using namespace std;
const char goal[5][6]={{"11111"},{"01111"},{"00*11"},{"00001"},{"00000"}};
const int dx[]={1,2,2,1,-1,-2,-2,-1};
const int dy[]={2,1,-1,-2,-2,-1,1,2};
char s[5][6];int T,ans;
inline bool same(){
    return !memcmp(s,goal,sizeof s); 
}
inline int deal(int dep){
    for(int i=0;i<5;i++)
        for(int j=0;j<5;j++)
            if(s[i][j]!=goal[i][j]) dep++;
    return dep;
}
void dfs(int dep){
    if(same()) ans=min(ans,dep-1);
    if(dep>=ans) return ;
    int x,y;
    for(int i=0;i<5;i++)
        for(int j=0;j<5;j++)
            if(s[i][j]=='*') x=i,y=j;
    for(int i=0;i<8;i++){
        x+=dx[i];y+=dy[i];
        if(x>=0&&x<5&&y>=0&&y<5){
            swap(s[x][y],s[x-dx[i]][y-dy[i]]);
            if(deal(dep)<=ans) dfs(dep+1);
            swap(s[x][y],s[x-dx[i]][y-dy[i]]);
        }
        x-=dx[i];y-=dy[i];
    }
}
int main(){
    cin>>T;
    while(T--){
        ans=16;
        for(int i=0;i<5;i++)
            for(int j=0;j<5;j++)
                cin>>s[i][j];
        dfs(1);
        cout<<(ans==16?-1:ans)<<endl;
    }
    return 0;
}

 

 

posted @ 2016-07-29 09:03  神犇(shenben)  阅读(312)  评论(0编辑  收藏  举报