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.

原文地址:https://www.cnblogs.com/mzh2017/p/8111033.html