SOJ2061 8 puzzle

来源:互联网 发布:关联规则和als矩阵 编辑:程序博客网 时间:2024/06/05 16:31

人生中第一次写A*,贡献了4TLE+4RE+4WA才换来一个宝贵的AC。

有几个地方需要总结的。

1.一定要判断开始局面能否到达结束局面,用逆序数判断。否则A*算法将搜索完所有可能的状态,导致TLE。

2.hash函数要选择好,一开始我直接使用了stl::map来hash,很慢,也会导致TLE。用逆序数列来保存状态,可以保证最多有362880个状态。

3.在把子节点加入开列表中时,不能直接将它的hash值设为已访问,在开列表中可能有多个重复但g不同的节点,应在取出节点时设为已访问。否则会WA。

4.不必把局势表示成3*3的矩阵,一维矩阵就可以了,更快,上下左右可以用-3,+3,-1,+1来表示。


#include <cstdio>#include <cstring>#include <queue>#include <algorithm>using namespace std;const int d[4]={1,-1,3,-3};int ans,a[10],b[10],bb[10][2];bool vis[400000];int c[9]={1,1,2,6,24,120,720,5040,40320};void swap(int &a, int &b){    int t=a;a=b;b=t;}bool inside(int i,int j){    if (i+j<0 || i+j>=9) return 0;    if (i%3==0 && j==-1) return 0;    if (i%3==2 && j==1) return 0;    return 1;}struct Node{    int num[10];    int f,g,h,hash;    bool operator < (const Node &o) const {return f>o.f;}    void geth()    {        h=0;        for (int i=0;i<9;i++)            if (num[i]) h+=abs(i/3-bb[num[i]][0])+abs(i%3-bb[num[i]][1]);    }    void gethash()    {        hash=0;        int cnt=0,zero;        for (int i=0;i<9;i++)        {            if (num[i]==0) {zero=i; continue;}            int k=0;            for (int j=0;j<i;j++)                if (num[j]>num[i]) k++;            hash+=k*c[cnt++];        }        hash+=(8-zero)*c[8];    }    void hehe()    {        gethash();        if (vis[hash]) return;        geth();        f=g+h;    }}t,tt;priority_queue<Node> Q;void Astar(){    while (!Q.empty()) Q.pop();    memset(vis,0,sizeof(vis));    for (int i=0;i<9;i++) t.num[i]=a[i];    t.g=0; t.hehe();    Q.push(t);    while (!Q.empty())    {        t=Q.top(); Q.pop();        if (vis[t.hash]) continue;        vis[t.hash]=1;        if (t.h==0) {ans=t.g; return;}        int zero;        for (int i=0;i<9;i++)            if (t.num[i]==0) zero=i;        for (int r=0;r<4;r++)        {            if (!inside(zero,d[r])) continue;            tt=t;            swap(tt.num[zero],tt.num[zero+d[r]]);            tt.g=t.g+1; tt.hehe();            if (vis[tt.hash]) continue;            Q.push(tt);        }    }}int main(){    int T,x;    scanf("%d",&T);    while (T--)    {        for (int i=0;i<9;i++) scanf("%d",&a[i]);        for (int i=0;i<9;i++) scanf("%d",&b[i]);        int inv=0;        for (int i=0;i<9;i++)            for (int j=0;j<i;j++)            {                if (a[i]&&a[j]&&a[i]<a[j]) inv++;                if (b[i]&&b[j]&&b[i]<b[j]) inv++;            }        if (inv&1)        {            puts("-1");            continue;        }        for (int i=0;i<9;i++)        {            x=b[i];            bb[x][0]=i/3;            bb[x][1]=i%3;        }        ans=-1;        Astar();        printf("%d\n",ans);    }    return 0;}


原创粉丝点击