hdu-1043 bfs+康拓展开hash

因为是计算还原成一种局面的最短步骤,应该想到从最终局面开始做bfs,把所有能到达的情况遍历一遍,把值存下来。

bfs过程中,访问过的局面的记录是此题的关键,9*9的方格在计算过程中直接存储非常占内存。而这个显然是12345678x的不同排列,考虑康拓展开来记录,每个局面hash成一个整数。步骤我先算了一下,最多有31步,我用4进制位hash成了两个整数来保存

#include <iostream>
#include <iomanip>
#include <set>
#include <cmath>
#include <string>
#include <algorithm>
#include <queue>
#include <vector>
#include <map>
#define LL long long
using namespace std;
class cantor
{
    public:
    #define siz 9
    char c[siz]={'1','2','3','4','5','6','7','8','x'};
    LL w[siz];
    bool vis[siz];
    cantor()
    {
        w[0]=1;
        for(int i=1;i<siz;i++)
            w[i]=w[i-1]*i;
    }
    void init()
    {
        for(int i=0;i<siz;i++)
            vis[i]=false;
    }
    LL makeCanto(string s)
    {
        init();
        LL rec=0;
        for(int i=0;i<siz;i++)
        {
            int d=0;
            for(int j=0;j<siz;j++)
            {
                if(vis[j])
                    continue;
                if(c[j]!=s[i])d++;
                else
                {
                    vis[j]=true;
                    break;
                }
            }
            rec+=w[siz-i-1]*d;
        }
        return rec;
    }
    string recover(LL val)
    {
        init();
        string s="";
        for(int i=siz-1;i>=0;i--)
        {
            LL te=val/w[i];
            val-=e*w[i];
            for(int j=0,cnt=-1;j<siz;j++)
            {
                if(vis[j])continue;
                else cnt++;
                if(cnt==te&&!vis[j])
                {
                    s+=c[j];
                    vis[j]=true;
                    break;
                }
            }
        }
        return s;
    }
};
LL n,m;
char mp[3][3];
set<LL> s;
string ss="";
const string las="12345678x";
bool f;
int dir[4][2]={-1,0,1,0,0,1,0,-1};
char dfuck[4]={'d','u','l','r'};
struct node
{
    LL s;
    int c;
    int x,y;
    LL a,b;
    node(LL ss,int aa,int X,int Y,LL A,LL B){s=ss;c=aa;x=X;y=Y;a=A;b=B;}
};
struct ax
{
    LL a,b,c;
    ax(LL A,LL B,LL C){a=A;b=B;c=C;}
    ax(){}
};
map<LL,ax> ans;
LL bit[18];
int main()
{
    cin.sync_with_stdio(false);
    cantor fx;
    bit[0]=1;
    for(int i=1;i<18;i++)
        bit[i]=bit[i-1]*4;
    queue<node> q;
    node ini=node(fx.makeCanto(las),0,2,2,0,0);
    q.push(ini);
    s.clear();
    ans.clear();
    int mx=0;
    s.insert(fx.makeCanto(las));
    while(!q.empty())
    {
        node now=q.front();
        ans[now.s]=ax(now.a,now.b,now.c);
        q.pop();
        mx=max(now.c,mx);
        for(int i=0;i<4;i++)
        {
            int yy=now.y+dir[i][0];
            int xx=now.x+dir[i][1];
            if(xx<0||yy<0||xx>=3||yy>=3)continue;
            string nx=fx.recover(now.s);
            swap(nx[now.y*3+now.x],nx[yy*3+xx]);
            LL nxv=fx.makeCanto(nx);
            if(s.find(nxv)!=s.end())continue;
            s.insert(nxv);
            LL na=now.a,nb=now.b;
            if(now.c<16)
            {
                na+=i*bit[now.c];
            }
            else
            {
                nb+=i*bit[now.c-16];
            }
            q.push(node(nxv,now.c+1,xx,yy,na,nb));
        }
    }
    while(cin>>mp[0][0]>>mp[0][1]>>mp[0][2]>>mp[1][0]>>mp[1][1]>>mp[1][2]>>mp[2][0]>>mp[2][1]>>mp[2][2])
    {
        int x,y;
        f=false;
        s.clear();
        ss="";
        for(int i=0;i<3;i++)
            for(int j=0;j<3;j++)
            {
                ss+=mp[i][j];
                if(mp[i][j]=='x')
                    y=i,x=j;
            }
        string o="";
        if(ss=="12345678x")
        {
            cout<<"lr"<<endl;
            continue;
        }
        if(ans.find(fx.makeCanto(ss))==ans.end())
        {
            cout<<"unsolvable"<<endl;
            continue;
        }
        ax fuck=ans[fx.makeCanto(ss)];
        for(int i=0;i<fuck.c;i++)
        {
            if(i<16)
            {
                o+=dfuck[fuck.a%4];
                fuck.a/=4;
            }
            else
            {
                o+=dfuck[fuck.b%4];
                fuck.b/=4;
            }
        }
        reverse(o.begin(),o.end());
        cout<<o<<endl;
    }
}

 

 

posted @ 2018-02-08 22:08  Luke_Ye  阅读(209)  评论(0编辑  收藏  举报