1. 程式人生 > 實用技巧 >hdu1430 康託展開+bfs預處理

hdu1430 康託展開+bfs預處理

hdu1430 魔板
傳送門
一個含有數字[1,8],兩行四列,具有八個方塊的魔板可以進行三種變換:
A.交換上下兩行
B.迴圈右移一列
C.中間4個方塊順時針旋轉
計算從初始狀態到目標狀態變換次數最小的方法中,字典序最小的那種。

康託展開+bfs預處理
將初始狀態全部對映為"01234567",目標狀態根據相同的對映函式對映成為相應的目標狀態。一次bfs預處理初始狀態為"01234567"的所有可達狀態,記錄每一步的操作。
因為實際移動是方塊之間位置的移動,數字只是一個標號,所以改變數字編號同樣可以表示方塊的位置移動。所以三種操作也可以通過預先設定陣列,記錄編號位置的變化來實現。

#include<iostream>
#include<cstdio>
#include<vector>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<cstring>
#include<string>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<functional>
using namespace std;

int fac[10]={1,1,2,6,24,120,720,5040,40320},book[60010];
int change[3][10]={{7,6,5,4,3,2,1,0},{3,0,1,2,5,6,7,4},{0,6,1,3,4,2,5,7}};
char s[10],t[10],g[10];
string ans[60010];

struct node{
    char str[8];
};

int cantor(char* a){
    int cnt,hash=0;
    for(int i=0;i<8;i++){
        cnt=0;
        for(int j=i+1;j<8;j++){
            if(a[j]<a[i]) cnt++;
        }
        hash+=cnt*fac[8-i-1];
    }
    return hash;
}

void bfs(){
    queue<node> q;
    node t1,t2;
    for(int i=0;i<8;i++) t1.str[i]=i+'0';
    int hash=cantor(t1.str);
    q.push(t1);
    book[hash]=1;
    while(!q.empty()){
        t1=q.front();
        q.pop();
        int h1=cantor(t1.str);
        for(int i=0;i<3;i++){
            for(int j=0;j<8;j++){
                t2.str[j]=t1.str[change[i][j]];
            }
            int h2=cantor(t2.str);
            if(book[h2]) continue;
            book[h2]=1;
            ans[h2]=ans[h1]+(char)(i+'A');
            q.push(t2);
        }
    }
}

int main(void){
    ios::sync_with_stdio(false);
    bfs();
    while(cin>>s>>t){
        for(int i=0;i<8;i++) g[s[i]-'0']=i;
        for(int i=0;i<8;i++) t[i]=g[t[i]-'0'];
        cout<<ans[cantor(t)]<<"\n";
    }
    return 0;
}