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[10];
};

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;
}
posted @ 2020-07-20 17:16  fxq1304  阅读(110)  评论(0编辑  收藏  举报