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;
}