您的位置:首页 > 其它

八数码第七境界——A*之曼哈顿+康托展开判重+回溯记录路径+逆序数判无解

2017-12-14 18:56 309 查看
(请先看前面6大境界)

A*其实就是以bfs为基础的,就是给了bfs一些条件,让它以优先队列的形式进行。

想快速掌握A*可以看http://blog.csdn.net/qq_36523667/article/details/78786160

A*有两种距离计算公式:

一种是曼哈顿距离:横向距离+纵向距离

一种是欧氏距离:两点间的直线距离

我们这里使用的是曼哈顿距离。

我们希望的路径假设是

4 8 7

1 2 x

5 6 3

我们的结束路径是

1 2 3

4 5 6

7 8 x

我们看到希望的路径和假设的路径1,相差1个位置,

2,相差1个位置,3相差2个位置。。。

就把所有的相差的位置的横向距离和纵向距离加起来求和,就粗略得出了我们至少应该移动的距离。之后我们在优先队列里,这个距离就是我们判断的依据。

上面这个求距离思想的代码表示

int len(node tmp)  

{  

    int ans=0;  

    for(int i=0;i<9;i++)  

    {  

        if(tmp.str[i]!='x')  

            ans+=abs(i/3-(tmp.str[i]-'0'-1)/3)+abs(i%3-((tmp.str[i]-'0')-1)%3);  

        else  

            ans+=(2-i/3)+(2-i%3);  

    }  

    return ans;  

}  

再给优先队列设置一下判断的依据(就是重写的这个<号)

struct node  

{  

    int r,w,hashnum,pos,num;  

    char str[10];  

    friend bool operator < (node a, node b)  

    {  

        if(a.r==b.r)return a.w > b.w;  

        return a.r > b.r;  

    }  

}tn;  

就行了

全部代码

#define N 512345  

  

char s[10];  

struct node  

{  

    int r,w,hashnum,pos,num;  

    char str[10];  

    friend bool operator < (node a, node b)  

    {  

        if(a.r==b.r)return a.w > b.w;  

        return a.r > b.r;  

    }  

}tn;  

struct res  

{  

    int now,fa;  

}res
;  

int  fac[] = {1,1,2,6,24,120,720,5040,40320};  

int vis
,hehe
;  

char init[10]="12345678x";  

bool inverse(char ss[])  

{  

    int t=0,x,y;  

    for(int i=1;i<9;i++)  

        for(int j=0;j<i;j++)  

        {  

            if(ss[j]=='x')continue;  

            else x=ss[j]-'0';  

            if(ss[i]=='x')continue;  

            else y=ss[i]-'0';  

            if(x>y)  

                t++;  

        }  

    if(t&1)  

        return true;  

    return false;  

}  

int KT(char ss[])  

{  

    int i, j, t, sum;  

    int s[10];  

    for(i=0;i<9;i++)  

    {  

        if(ss[i]=='x')  

            s[i]=0;  

        else  

            s[i]=ss[i]-'0';  

    }  

    sum = 0;  

    for (i=0; i<9; i++)  

    {  

        t = 0;  

        for (j=i+1; j<9; j++)  

            if (s[j] < s[i])  

                t++;  

        sum += t*fac[9-i-1];  

    }  

    return sum+1;  

}  

int len(node tmp)  

{  

    int ans=0;  

    for(int i=0;i<9;i++)  

    {  

        if(tmp.str[i]!='x')  

            ans+=abs(i/3-(tmp.str[i]-'0'-1)/3)+abs(i%3-((tmp.str[i]-'0')-1)%3);  

        else  

            ans+=(2-i/3)+(2-i%3);  

    }  

    return ans;  

}  

int Astar(int now)  

{  

    char c;  

    priority_queue<node> q;  

    while(!q.empty())q.pop();  

    node g,h;  

    int over = KT(init);  

    for(int i=0;i<10;i++)  

        g.str[i]=s[i];  

    g.hashnum=KT(g.str);g.pos=now;g.num=0;  

    g.r=len(g);g.w=0;  

    vis[g.hashnum]=g.num;  

    q.push(g);  

    int cnt=1;  

    while(!q.empty())  

    {  

        g=q.top();q.pop();  

        if(g.hashnum==over)  

            return g.num;  

        h=g;  

        if((h.pos+1)%3!=0)  

        {  

            c=h.str[h.pos];h.str[h.pos]=h.str[h.pos+1];h.str[h.pos+1]=c;  

            h.pos++;  

            h.w++;h.r=len(h);h.hashnum=KT(h.str);  

            res[cnt].now=4;res[cnt].fa=h.num;h.num=cnt;cnt++;  

            if(vis[h.hashnum]==-1)  

            {  

                vis[h.hashnum]=cnt-1;  

                q.push(h);  

            }  

        }  

        h=g;  

        if(h.pos%3!=0)  

        {  

            c=h.str[h.pos];h.str[h.pos]=h.str[h.pos-1];h.str[h.pos-1]=c;  

            h.pos--;  

            h.w++;h.r=len(h);h.hashnum=KT(h.str);  

            res[cnt].now=3;res[cnt].fa=h.num;h.num=cnt;cnt++;  

            if(vis[h.hashnum]==-1)  

            {  

                vis[h.hashnum]=cnt-1;  

                q.push(h);  

            }  

        }  

        h=g;  

        if(h.pos<6)  

        {  

            c=h.str[h.pos];h.str[h.pos]=h.str[h.pos+3];h.str[h.pos+3]=c;  

            h.pos+=3;  

            h.w++;h.r=len(h);h.hashnum=KT(h.str);  

            res[cnt].now=2;res[cnt].fa=h.num;h.num=cnt;cnt++;  

            if(vis[h.hashnum]==-1)  

            {  

                vis[h.hashnum]=cnt-1;  

                q.push(h);  

            }  

        }  

        h=g;  

        if(h.pos>2)  

        {  

            c=h.str[h.pos];h.str[h.pos]=h.str[h.pos-3];h.str[h.pos-3]=c;  

            h.pos-=3;  

            h.w++;h.r=len(h);h.hashnum=KT(h.str);  

            res[cnt].now=1;res[cnt].fa=h.num;h.num=cnt;cnt++;  

            if(vis[h.hashnum]==-1)  

            {  

                vis[h.hashnum]=cnt-1;  

                q.push(h);  

            }  

        }  

    }  

    return -1;  

}  

int main()  

{  

    int i,j,k,kk,t,x,y,z;  

    while(scanf("%s",s)!=EOF)  

    {  

        if(s[0]=='x')x=0;  

        for(i=1;i<9;i++)  

        {  

            scanf("%s",s+i);  

            if(s[i]=='x')x=i;  

        }  

        if(inverse(s))  

        {  

            printf("unsolvable\n");  

            continue;  

        }  

        res[0].now=-1;  

        memset(vis,-1,sizeof(vis));  

        t = Astar(x);  

        x=0;  

        while(res[t].now!=-1)  

            hehe[x++]=res[t].now,t=res[t].fa;  

        for(i=x-1;i>=0;i--)  

        {  

            if(hehe[i]==1)printf("u");  

            if(hehe[i]==2)printf("d");  

            if(hehe[i]==3)printf("l");  

            if(hehe[i]==4)printf("r");  

        }  

        printf("\n");  

    }  

    return 0;  

}  

补充一点。

struct node  

{  

    int r,w,hashnum,pos,num;  

    char str[10];  

    friend bool operator < (node a, node b)  

    {  

        if(a.r==b.r)return a.w > b.w;  

        return a.r > b.r;  

    }  

}tn;  

这里的重载<号的判断我们需要深究一下。

return a.r > b.r;是代表我们的优先队列优先把剩下的曼哈顿距离最短的放在队列最前面。

那么上面那个if(a.r==b.r)return a.w > b.w;  呢?就是当曼哈顿距离相等的时候,我们就看我们已经走出去的步数。如果走出去的步数越多,我们更倾向于把他放在队列的最前面。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: