zoukankan      html  css  js  c++  java
  • BZOJ1085 SCOI2005 骑士精神【IDA* 启发式迭代加深】

    BZOJ1085 SCOI2005 骑士精神


    Description

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

    Input

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

    Output

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

    Sample Input

    2
    10110
    01*11
    10111
    01001
    00000
    01011
    110*1
    01110
    01010
    00100

    Sample Output

    7
    -1


    先看着题,有步数限制,范围又是5*5的,显然是搜索题,但是我们可以发现,强行爆搜只有死路一条。根据步数限制我们可以想到迭代加深,因为每次加深层数复杂度成指数级,所以大体可以忽略复杂度影响。但是迭代加深之后还是不够怎么办?启发式判断,如果一个状态到最优状态的期望最小距离大于当前的最小步数,直接排除这个状态。然后就可以愉快地AC了。


    #include<bits/stdc++.h>
    using namespace std;
    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 mx[8]={1,1,-1,-1,2,2,-2,-2};
    int my[8]={2,-2,2,-2,1,-1,1,-1};
    int flag;
    bool judge(int a[5][5]){
        if(a[2][2]!=ans[2][2])return 0;
        for(int i=0;i<5;i++)
            for(int j=0;j<5;j++)
                if(a[i][j]!=ans[i][j])return 0;
        return 1;
    }
    bool cost(int a[5][5],int s,int k){
        int v=0;
        for(int i=0;i<5;i++)
            for(int j=0;j<5;j++)
                if(a[i][j]!=ans[i][j]){
                    v++;
                    if(v+s>k)return 0;
                }
        return 1;
    }
    void search(int s,int k,int a[5][5],int x,int y){
        if(s==k){
            if(judge(a))flag=1;
            return;
        }
        if(flag==1)return;
        for(int i=0;i<8;i++){
            int nx=x+mx[i],ny=y+my[i];
            if(nx<0||nx>4||ny<0||ny>4)continue;
            swap(a[x][y],a[nx][ny]);
            if(cost(a,s,k))search(s+1,k,a,nx,ny);
            swap(a[x][y],a[nx][ny]);
        }
    }
    int main(){
        //freopen("1085.in","r",stdin);
        //freopen("1085.out","w",stdout);
        int T;scanf("%d",&T);
        while(T--){
            int a[5][5],x,y;char ch[10];
            memset(a,0,sizeof(a));
            flag=0;
            for(int i=0;i<5;i++){
                scanf("%s",ch);
                for(int j=0;j<5;j++){
                    if(ch[j]=='*')a[i][j]=2,x=i,y=j;
                    else a[i][j]=ch[j]-'0';
                }
            }
            for(int k=1;k<=15;k++){
                search(0,k,a,x,y);
                if(flag){
                    printf("%d
    ",k);
                    break;
                }
            }
            if(!flag)printf("-1
    ");
        }
        return 0;
    }
  • 相关阅读:
    Ubuntu 装JDK
    U盘文件夹被病毒隐藏,且不能取消解决办法
    wireshark: there are no interfaces on which a capture can be done
    [转]Ubuntu 常用快捷键10个
    恢复被win7覆盖的Ubuntu Grub
    U盘安装Win7 64位
    荣耀3X畅玩版狙击红米note!
    Secret and Whisper
    360 chrome不能登录Google账户
    周鸿祎仍想做手机
  • 原文地址:https://www.cnblogs.com/dream-maker-yk/p/9676398.html
Copyright © 2011-2022 走看看