CDOJ 485 UESTC 485 Game (八数码变形,映射,逆cantor展开)

题意:八数码,但是转移的方式是转动,一共十二种,有多组询问,初态唯一,终态不唯一。

题解:初态唯一,那么可以预处理出012345678的所有转移情况,然后将初态对012345678做一个映射,再枚举一下终态的所有情况,取最小值即可。

不得不学了逆cantor展开,cantor展开是一个变进制数,每位上是原序列对应位置上的逆序值。那么求逆时候,就先除最大的位权得到对应位置上的逆序值,根据逆序值可以知道他在原序列中第几大,然后标记它,迭代。状态转移有点烦。一开始还担心超时,就打了个表直接存到程序里,结果超过30000bit代码长度限制了,笑cry。

#include<cstdio>

#include<cmath>

#include<vector>

#include<map>

#include<set>

#include<algorithm>

#include<iostream>

#include<cstring>

#include<queue>

using namespace std;

typedef long long ll;

//#define local



const int maxn = 362880;

int d[maxn];

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

int St[9],Ed[9];



int cantor(int *e) {

        int ret = 0;

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

            int cnt = 0;

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

                if(e[j] < e[i]) cnt++;

            ret += fac[8-i] * cnt;

        }

        return ret;

}



void invCantor(int *a,int code)

{

    bool vis[10] = {0};

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

        int t = code/fac[8-i];

        int j;

        for( j = 0; j < 9 ; j++){

            if(!vis[j]){

                if(t == 0) break;

                t--;

            }

        }

        a[i] = j; vis[j] = 1;

        code %= fac[8-i];

    }

}



int dir[12][9] = {

{2,0,1,3,4,5,6,7,8},{0,1,2,5,3,4,6,7,8},{0,1,2,3,4,5,8,6,7},

{1,2,0,3,4,5,6,7,8},{0,1,2,4,5,3,6,7,8},{0,1,2,3,4,5,7,8,6},

{6,1,2,0,4,5,3,7,8},{0,7,2,3,1,5,6,4,8},{0,1,8,3,4,2,6,7,5},

{3,1,2,6,4,5,0,7,8},{0,4,2,3,7,5,6,1,8},{0,1,5,3,4,8,6,7,2} };

queue<int> q;



void BfsPre()

{

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

    d[0] = 0;

    q.push(0);

    while(q.size()){

        int u = q.front();q.pop();

        int tmp[9];

        invCantor(tmp,u);

        for(int i = 0; i < 12; i++){

            int tmp2[9];

            for(int j = 0; j < 9; j++){

                tmp2[j] = tmp[dir[i][j]];

            }

            int v = cantor(tmp2);

            if(~d[v]) continue;

            d[v] = d[u]+1;

            q.push(v);

        }

    }

}





int query()

{

    int mp[9];

    for(int i = 0; i < 9; i++) { mp[St[i]] = i; }

    bool appear[9] = {0};

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

       if(~Ed[i]) appear[Ed[i] = mp[Ed[i]]] = 1;

    }

    int vec[9],sz = 0;

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

        if(!appear[i]) vec[sz++] = i;

    }

    if(sz == 9)  return 0;

    if(sz == 0) return d[cantor(Ed)];

const int INF =  0x7fffffff;

    int ans = INF;

    int tmp[9];

     do{

        int j = 0;

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

            if(~Ed[i]) { tmp[i] = Ed[i]; }

            else { tmp[i] = vec[j++]; }

        }

        int Hash = cantor(tmp);

        if(~d[Hash]) ans = min(ans,d[Hash]);

    }while(next_permutation(vec,vec+sz));

    return ans!=INF? ans : -1;

}





int main()

{

#ifdef local

    freopen("in.txt","r",stdin);

    //freopen("out.txt","w",stdout);

#endif // local

    int T;

    BfsPre();



    scanf("%d",&T);

    for(int k = 1; k <= T; k++){

        printf("Case #%d: ",k);

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

            scanf("%d",St+i);

            St[i]--;

        }

        getchar();

        char buf[15];

        for(int i = 0; i < 3; i++){

            gets(buf);

            for(int j = 0; j < 5; j+=2){

                if('1'<=buf[j] && buf[j] <= '9'){

                    Ed[i*3+j/2] = buf[j] - '1';

                }else Ed[i*3+j/2] = -1;

            }

        }

        int ans = query();

        if(~ans) printf("%d\n",ans);

        else printf("No Solution!\n");

    }



    return 0;

}

 

你可能感兴趣的:(game)