• P2324 [SCOI2005]骑士精神(A*)


    P2324 [SCOI2005]骑士精神

    A*与爆搜的不同就是它有一个估价函数$h(x)$

    这个估价函数一般设为从当前状态到终点状态的估计最短步数,这样可以有效剪枝

    但估计值必须严格小于等于实际剩余步数,否则会剪枝过度而影响正确性

    $g(x),f(x)$分别为剩余步数和已走步数,则:

    $g(x)=f(x)+h(x)$

    本题中的$h(x)$可以设为未归位的棋子数+1

    因为每一步最多使一个棋子归位(除最后一步一次归位2个棋子)

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    
    int d1[8]={1,1,2,2,-1,-1,-2,-2};
    int d2[8]={2,-2,1,-1,2,-2,1,-1};
    char a[9][9]; int re,col[9][9];
    inline bool is(int x,int y){return (x==3&&y==3)?(a[x][y]=='*'):(a[x][y]==col[x][y]+'0');}
    void dfs(int d,int s,int x,int y){//d当前步数,s已归位棋子个数
        if(d+24-s>=re||d>15) return ;//f(x)=d,g(x)=24-s
        if(s==25) {re=min(re,d); return ;}
        for(int i=0;i<8;++i){
            int rx=x+d1[i],ry=y+d2[i],p=s;
            if(rx<1||5<rx||ry<1||5<ry) continue;
            p-=is(x,y)+is(rx,ry);
            swap(a[x][y],a[rx][ry]);
            p+=is(x,y)+is(rx,ry);
            dfs(d+1,p,rx,ry);
            swap(a[x][y],a[rx][ry]);
        }
    }
    int main(){
        for(int i=1;i<=5;++i) for(int j=i;j<=5;++j) col[i][j]=1;
        col[4][4]=col[5][5]=0;
        int T,sum,fx,fy;scanf("%d",&T);
        while(T--){
            sum=0; re=16;
            for(int i=1;i<=5;++i){
                scanf("%s",a[i]+1);
                for(int j=1;j<=5;++j){
                    sum+=is(i,j);
                    if(a[i][j]=='*') fx=i,fy=j;
                }
            }dfs(0,sum,fx,fy);
            if(re>15) re=-1;
            printf("%d
    ",re);
        }return 0;
    } 
  • 相关阅读:
    有一天,我们能这样相爱吗?
    端午节来源六说
    一个ini类代替缓存使用
    创意生活可爱香皂
    漂亮的韩国发饰
    Oracle中PL/SQL单行函数和组函数详解
    真正爱你的女人是这样的
    执子之手,与子偕老。你同意么?
    男人如茶
    Oracle SQL 內置函數大全
  • 原文地址:https://www.cnblogs.com/kafuuchino/p/11285586.html
Copyright © 2020-2023  润新知