• a*


    a*算法

    这里用八数码问题做样例:

    1.康托展开判重

    2.openlist存待拓展的状态,closelist存已拓展的状态,len1表示openlist(简称ol)的长度(不真实),len2表示closelis(简称cl)t的真实长度,real存openlist的真实长度。

      visit[i]表示i状态是否被转移过,inclose[i]表示i状态是否在closelist中。

    3.对于h(i)函数,用各个数字到目标状态的曼哈顿距离之和来求。

    4.a*的具体步骤:

      a.初始状态为from,则在ol中加入from,将ol[1].g=0,ol[1].p=-1(寻找答案路径的终点||其实可以不用),ol[1].h=0(可为任意值)

      b.重复一下步骤直至real=0

        (1).取出ol[i]中ol[i].g+ol[i].h且inclose[i]=0最小的状态i;

        (2).拓展i的状态

          如果visit[j]==0,则拓展j并计算其g值,h值

          如果visit[j]==1同时inclose[j]==1,跳过

          如果visit[j]==1同时inclose[j]==0,则更新j的g值

        (3).将i加入到cl中,并将inclose[i]赋值成1,如果i是目标状态则输出i的g值,跳出

      c.如果real=0,则没有答案.

      d.结束.

    5.对于大佬来说inclose数组其实可以用堆优化代价.蒟蒻在这里就不加以介绍了。

    6.代码(努力构建中......)

    期望的得分:tle 0

    #include<cmath>
    #include<cstdio>
    #include<iostream>
    using namespace std;
    struct tonod{
        int g,h,k;
        long long n;
    }ol[4000000],cl[1000000];
    struct pair{
        int x,y;
    }w[10];
    int visit[1000000],len1=1,len2=0,real=1;
    bool ic[4000000];
    long long from;
    long long bas[10]={1,1,2,6,24,120,720,5040,40320,362880},a[9]={1,10,100,1000,10000,100000,1000000,10000000,100000000};
    int cantor(long long x)
    {
        int wei[10];
        for(int i=1;i<=9;i++)
        wei[i]=x/a[9-i]%10;
        int ans=0;
        for(int i=1;i<=9;i++)
        {
            int tmp=0;
            for(int j=i+1;j<=9;j++)
            if(wei[j]<wei[i])
            tmp++;
            ans+=tmp*bas[9-i];
        }
        return ans;
    }
    int geth(long long x)
    {
        int h=0,top=1;
        for(int i=1;i<=3;i++)
        for(int j=1;j<=3;j++)
        {
            h+=abs(w[x/a[9-top]%10].x-i)+abs(w[x/a[9-top]%10].y-j);
            top++;
        }
        return h;
    }
    void up(int k)
    {
        int xx=ol[k].k;
        if(xx-3<1)
        return;
        long long x=ol[k].n;
        int wei=x/a[9-(xx-3)]%10;
        x=x-wei*a[9-(xx-3)]+wei*a[9-xx];
        int tmp=cantor(x);
        if(visit[tmp]==0)
        {
            len1++;
            real++;
            visit[tmp]=len1;
            tonod c;
            c.k=xx-3;
            c.n=x;
            c.g=ol[k].g+1;
            c.h=geth(x);
            ol[len1]=c;
        }
        else
        if(!ic[tmp])
        {
            int tmp1=visit[tmp];
            if(ol[tmp1].g>ol[k].g+1)
            ol[tmp1].g=ol[k].g+1;
        }
    }
    void down(int k)
    {
        int xx=ol[k].k;
        if(xx+3>9)
        return;
        long long x=ol[k].n;
        int wei=x/a[9-(xx+3)]%10;
        x=x-wei*a[9-(xx+3)]+wei*a[9-xx];
        int tmp=cantor(x);
        if(visit[tmp]==0)
        {
            len1++;
            real++;
            visit[tmp]=len1;
            tonod c;
            c.k=xx+3;
            c.n=x;
            c.g=ol[k].g+1;
            c.h=geth(x);
            ol[len1]=c;
        }
        else
        if(!ic[tmp])
        {
            int tmp1=visit[tmp];
            if(ol[tmp1].g>ol[k].g+1)
            ol[tmp1].g=ol[k].g+1;
        }
    }
    void left(int k)
    {
        int xx=ol[k].k;
        if(xx==1||xx==4||xx==7)
        return;
        long long x=ol[k].n;
        int wei=x/a[9-(xx-1)]%10;
        x=x-wei*a[9-(xx-1)]+wei*a[9-xx];
        int tmp=cantor(x);
        if(visit[tmp]==0)
        {
            len1++;
            real++;
            visit[tmp]=len1;
            tonod c;
            c.k=xx-1;
            c.n=x;
            c.g=ol[k].g+1;
            c.h=geth(x);
            ol[len1]=c;
        }
        else
        if(!ic[tmp])
        {
            int tmp1=visit[tmp];
            if(ol[tmp1].g>ol[k].g+1)
            ol[tmp1].g=ol[k].g+1;
        }
    }
    void right(int k)
    {
        int xx=ol[k].k;
        if(xx==3||xx==6||xx==9)
        return;
        long long x=ol[k].n;
        int wei=x/a[9-(xx+1)]%10;
        x=x-wei*a[9-(xx+1)]+wei*a[9-xx];
        int tmp=cantor(x);
        if(visit[tmp]==0)
        {
            len1++;
            real++;
            visit[tmp]=len1;
            tonod c;
            c.k=xx+1;
            c.n=x;
            c.g=ol[k].g+1;
            c.h=geth(x);
            ol[len1]=c;
        }
        else
        if(!ic[tmp])
        {
            int tmp1=visit[tmp];
            if(ol[tmp1].g>ol[k].g+1)
            ol[tmp1].g=ol[k].g+1;
        }
    }
    int main()
    {
        scanf("%lld",&from);
        w[1].x=1;w[1].y=1;w[2].x=2;w[2].y=1;w[3].x=3;w[3].y=1;
        w[8].x=1;w[8].y=2;w[0].x=2;w[0].y=2;w[4].x=3;w[4].y=2;
        w[7].x=1;w[7].y=3;w[6].x=2;w[6].y=3;w[5].x=3;w[5].y=3;
        tonod r;
        r.g=0;r.h=0;r.n=from;
        int wei[10];
        int k; 
        for(int i=1;i<=9;i++)
        {
            wei[i]=from/a[9-i]%10;
            if(wei[i]==0)
            {
                k=i;
                break;
            }
        }
        r.k=k;
        ol[1]=r;
        visit[cantor(from)]=1;
        while(real!=0)
        {
            int minn=99999999,tmp;
            for(int i=1;i<=len1;i++)
            if(ol[i].h+ol[i].g<=minn&&!ic[cantor(ol[i].n)])
            {
                tmp=i;
                minn=ol[i].h+ol[i].g;
            }
            up(tmp);
            down(tmp);
            left(tmp);
            right(tmp);
            cl[++len2]=ol[tmp];
            ic[cantor(ol[tmp].n)]=1;
            real--;
            if(cl[len2].n==123804765)
            {
                printf("%d",cl[len2].g);
                return 0;
            }
        }
        printf("No Answer!");
    } 
    View Code

    所以进行dfs优化(状态判重减少,康托展开代价减少,剪枝增加,搜索减少)期望:100

    具体思路:

    (1)枚举搜索深度k

    (2)对于深度为k的进行dfs(剪枝用估价函数的值加上g值,若大于深度k则剪掉

    (3)第一次出的答案即为最优解。

     1 #include<cmath>// a* by 八重 樱 
     2 #include<cstdio>
     3 #include<iostream>
     4 using namespace std;
     5 int ans1=0,num[4][4];
     6 int X,Y;
     7 int dx[4]={0,1,-1,0};//横坐标移动 
     8 int dy[4]={1,0,0,-1};//纵坐标移动 
     9 int fx[11]={0,1,1,1,2,3,3,3,2};//目标状态的横坐标 
    10 int fy[11]={0,1,2,3,3,3,2,1,1};//目标状态的纵坐标 
    11 int geth()//曼哈顿距离求估价函数 
    12 {
    13     int ans=0;
    14     for(int i=1;i<=3;i++)
    15     for(int j=1;j<=3;j++)
    16     if(num[i][j])
    17     ans+=abs(i-fx[num[i][j]])+abs(j-fy[num[i][j]]);
    18     return ans;
    19 }
    20 void dfs(int k,int a,int b,int g)//完美的深搜 k枚举的深度 
    21 {
    22     int h=geth();
    23     if(!h)
    24     {
    25         ans1=g;
    26         return;
    27     }
    28     if(h+g>k||ans1||g==k)//剪枝 
    29     return;
    30     for(int i=0;i<4;i++)
    31     {
    32         int c=dx[i]+a;
    33         int d=dy[i]+b;
    34         if(c>=1&&d>=1&&c<=3&&d<=3)
    35         {
    36             swap(num[a][b],num[c][d]);
    37             dfs(k,c,d,g+1);
    38             swap(num[a][b],num[c][d]);
    39         }
    40     }
    41 }
    42 int main()
    43 {
    44     for(int i=1;i<=3;i++)
    45     for(int j=1;j<=3;j++)
    46     {
    47         char s;
    48         scanf("%c",&s);
    49         num[i][j]=s-'0';
    50         if(!num[i][j])
    51         X=i,Y=j;
    52     }
    53     for(int k=1;k<=10000;k++)
    54     {
    55         dfs(k,X,Y,0);
    56         if(ans1)
    57         {
    58             printf("%d",ans1);
    59             return 0;
    60         }
    61     }
    62 }
    View Code

    OVER,By Yae Sakura.

  • 相关阅读:
    gateway调用Fegin失败问题解决
    JVM调试命令简介
    oracle10g登录em后,提示“java.lang.Exception: Exception in sending Request :: null”
    vs2019中让ashx 文件中折叠收起代码
    oracle多表视图不自动更新,手动刷新视图获得基本表的数据
    可以对表单中的隐藏字段进行操纵 问题参数 __VIEWSTATEGENERATOR
    SQL Server 检测到基于一致性的逻辑 I/O 错误 页撕裂
    WIN2016和WIN10关闭同步主机服务,节省磁盘频繁读取,并关闭自动维护
    IIS网站应用程序配置不继承网站.net框架版本
    c#web错误码CS0227,不安全代码只会在使用/unsafe编译情况下出现
  • 原文地址:https://www.cnblogs.com/mzh2017/p/8111033.html
Copyright © 2020-2023  润新知