洛谷 P2578 [ZJOI2005]九数码游戏【bfs+康托展开】

只有9!=362880个状态,用康托展开hash一下直接bfs即可

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int N=1000005,fac[]={1,1,2,6,24,120,720,5040,40320,362880},d1[]={4,1,2,7,5,3,8,9,6},d2[]={1,2,3,6,4,5,7,8,9};
int a[15],b[15],v[15],dis[N],la[N],tot;
long long s,t=123456789,ans[N];
int has(long long x)
{
    for(int i=9;i>=1;i--)
        a[i]=x%10,x/=10;
    int r=0;
    for(int i=1,sm;i<=9;i++)
    {
        sm=0;
        for(int j=i+1;j<=9;j++)
            if(a[j]<a[i])
                sm++;
        r+=fac[9-i]*sm;
    }
    return r;
}
long long rel(int x)
{
    memset(v,0,sizeof(v));
    long long r=0;
    for(int i=9;i>=1;i--)
    {
        int t=x/fac[i-1];
        x%=fac[i-1];
        for(int j=1,w=0;j<=9;j++)
            if(!v[j])
            {
                w++;
                if(w==t+1)
                {
                    r=r*10+j;
                    v[j]=1;
                    break;
                }
            }
    }
    return r;
}
int main()
{
    for(int i=1,x;i<=9;i++)
        scanf("%d",&x),s=s*10+x+1;
    s=has(s),t=has(t);//cerr<<s<<" "<<t<<"   "<<rel(s)<<" "<<rel(t)<<endl;
    queue<int>q;
    dis[s]=1;
    q.push(s);
    while(!q.empty())
    {
        int u=q.front();//cerr<<u<<endl<<rel(u)<<endl;
        q.pop();
        if(u==t)
            break;
        long long x=rel(u),v1=0,v2=0;
        for(int i=9;i>=1;i--)
            a[i]=x%10,x/=10;
        for(int i=0;i<9;i++)
            v1=v1*10+a[d1[i]],v2=v2*10+a[d2[i]];//cerr<<v1<<" "<<v2<<endl;
        v1=has(v1),v2=has(v2);//cerr<<v1<<" "<<v2<<endl;
        if(!dis[v1])
            la[v1]=u,dis[v1]=dis[u]+1,q.push(v1);
        if(!dis[v2])
            la[v2]=u,dis[v2]=dis[u]+1,q.push(v2);
    }
    if(!dis[t])
    {
        puts("UNSOLVABLE");
        return 0;
    }
    printf("%d\n",dis[t]-1);
    for(int i=t;i!=s;i=la[i])
        ans[++tot]=rel(i);
    ans[++tot]=rel(s);
    for(int i=tot;i>=1;i--)
    {
        for(int j=1;j<=9;j++)
            a[j]=ans[i]%10-1,ans[i]/=10;
        printf("%d %d %d\n%d %d %d\n%d %d %d\n\n",a[9],a[8],a[7],a[6],a[5],a[4],a[3],a[2],a[1]);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/lokiii/p/9770958.html