Aizu 0121 Seven Puzzle(变进制数的完美hash)

一遍预处理跑完所有情况,O(1)回答就好。状态记录我用的康拓和逆康拓。

#include<bits/stdc++.h>
using namespace std;

int d[40320];
int fac[8];
int u[8];

int cantor()
{
    int re = 0;
    for(int i = 0; i < 8; i++){
        int inv = 0;
        for(int j = i; ++j < 8; ){
            if(u[i]>u[j]) inv++;
        }
        re += fac[7-i]*inv;
    }
    return re;
}

void invCantor(int x)
{
    bool vis[8] = {};
    for(int i = 0; i < 8; i++){
        int w = x/fac[7-i];
        x %= fac[7-i];
        int j = 0;
        for( ; j < 8; j++){
            if(!vis[j]){
                if(!w) break;
                w--;
            }
        }
        u[i] = j; vis[j] = true;
    }
}

int cur;
queue<int> q;

inline void updata(int p0,int p1)
{
    swap(u[p0],u[p1]);
    int s = cantor();
    if(!d[s]){
        d[s] = d[cur]+1;
        q.push(s);
    }
    swap(u[p0],u[p1]);
}

void bfs()
{
    d[0] = 1;
    q.push(0);
    while(q.size()){
        invCantor(cur = q.front()); q.pop();
        int p;
        for(int i = 0; i < 8; i++)
            if(!u[i]){ p = i; break; }
        int r = p%4;
        if(r) {
            updata(p-1,p);
        }
        if(r<3){
            updata(p+1,p);
        }
        updata(p,p+(p>3?-4:4));
    }
}

void preDeal()
{
    fac[0] = 1;
    for(int i = 1; i < 8; i++){
        fac[i] = fac[i-1]*i;
    }
    bfs();
}

int read()
{
    if(scanf("%d",u)<0) return -1;
    for(int i = 1; i < 8; i++) scanf("%d",u+i);
    return cantor();
}

//#define LOCAL
int main()
{
#ifdef LOCAL
    freopen("in.txt","r",stdin);
#endif
    preDeal();
    int s;
    while( ~(s = read()) ){
        printf("%d
",d[s]-1);
    }
    return 0;
}