• [启发式搜索/A*] [SCOI2005]骑士精神题解


    洛谷-骑士精神

    启发式搜索-A*

    估价函数

    对于当前状态,我们可以将其与目标状态对比,得到一个预估的代价,即最少(不一定满足题意)的代价,得到这个代价的函数叫做估价函数

    对于一个最短路问题来说,我们可以定义一个如下的函数式来表示搜索的过程

    [f^*(x)=g^*(x)+h^*(x) ]

    其中,f*(x)为从x到目标节点预估的总代价,g*(x)表示目前到达x点已经付出的代价,h*(x)表示预估从x到目标的最小代价,如上题(骑士精神)中,f(x)用迭代加深枚举出来,g(x)为已经走的步数(已知),h*(x)则可表示为目前局面与目标局面的不同点的个数。

    上题代码

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    int a[5][5];
    int _std[5][5]= {
        {1,1,1,1,1},
        {0,1,1,1,1},
        {0,0,-1,1,1},
        {0,0,0,0,1},
        {0,0,0,0,0}
    };
    int dx[]={0,-2,-2,-1,-1,1,1,2,2};    //重点,剪枝,两边对称并在下面判断防止走回去
    int dy[]={0,-1,1,-2,2,-2,2,-1,1};
    int ans;
    int lim;
    int fc()
    {
        int ret=0;
        for(int i=0; i<5; i++) {
            for(int j=0; j<5; j++) {
                if(a[i][j]!=_std[i][j]) {
                    ret++;
                }
            }
        }
        return ret;
    }
    void dfs(int x,int y,int step,int f)
    {
        int diff=fc();
        if(diff+step>lim)return;
        if(step>=ans)return;
        if(diff==0) {
            ans=step;
            return;
        }
        for(int i=1; i<=8; i++) {
            if(x+dx[i]<0||(x+dx[i]>4)) continue;
            if(y+dy[i]<0||(y+dy[i]>4)) continue;
            if(i+f!=9) {
                swap(a[x+dx[i]][y+dy[i]],a[x][y]);
                dfs(x+dx[i],y+dy[i],step+1,i);
                swap(a[x+dx[i]][y+dy[i]],a[x][y]);
            }
        }
    }
    
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--) {
            int x,y;
            ans=20;
            int dif=0;
            for(int i=0; i<5; i++) {
                for(int j=0; j<5; j++) {
                    char tmp;
                    cin>>tmp;
                    if(tmp=='1') {
                        a[i][j]=1;
                    }
                    if(tmp=='0') {
                        a[i][j]=0;
                    }
                    if(tmp=='*') {
                        a[i][j]=-1;
                        x=i;
                        y=j;
                    }
                    if(a[i][j]!=_std[i][j])dif++;
                }
            }
            for(int i=dif;i<=16;i++){
                lim=i;
                dfs(x,y,0,0);
            }
            printf("%d
    ",ans==20? -1:ans);
        }
        return 0;
    }
    

    而对于上题的搜索则需要最优性剪枝,通过变化数组的遍历方式防止走回去

  • 相关阅读:
    PHP获取某年第几周的开始日期和结束日期
    Java多线程(一)
    Java多线程学习
    使用反射实现 webdriver page 类
    PageObjects 设计模式
    Selenium WebDriver 工作原理
    Selenium2.0 Webdriver 随笔
    Selenium-Grid2 配置RemoteWebDriver
    Java多线程基础(二)
    Java多线程基础(一)
  • 原文地址:https://www.cnblogs.com/shulker/p/9832596.html
Copyright © 2020-2023  润新知