打卡 day3
这是一个3X3的数字华容道,我一开始也是毫无头绪,然后去看佬们的博客。
首先是康托展开
感觉看进去之后很简单,对应到这道题上就是把1~8进行全排列,应用康托展开能确定当前的排列名次,先看比首位小的数有几个,记作a,然后再看第二位,记作b…注意已经用过的数不计入后面位数数字的统计中(比如3412,比3小的有1,2,记a=2,比4小的有1,2,3,但之前已经出现过3,所以只考虑1,2,记b=2…)
最后由公式可得X=a·7!+b·6!+c·5!+d·4!+e·3!+f·2!+g·1!+h·0!
我们可以说,当前的排列之前有X位,当前的排列排在第X+1位。
康托和逆康托就当成板子用吧,思路是知道了。
这道题就是存储每个时刻的顺序用康托存了起来,表示一种情况,实现hash存储。逆bfs也就是从最终结果({1,2,3},{4,5,6},{7,8,x})出发,直到搜到输入的样例康托值为止,这样做是因为多组输入,预先把答案都存到了path字符串数组中。
#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<string>
#include<cstring>
#include<vector>
using namespace std;
const int maxn=362880+10;
int fac[]={1,1,2,6,24,120,720,5040,40320,362880};
struct node{
string path;
int hash;
int pos;
}now,st;
queue<node> q;
int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
char opp[5]={'u','d','l','r'};
int temp[9];
int result=46234;
string path[maxn];
int vis[maxn];
int cantor(int *a){
int x=0;
for(int i=0;i<9;i++){
int smaller=0;
for(int j=i+1;j<9;j++){
if(a[j]<a[i]) smaller++;
}
x+=fac[9-i-1]*smaller;
}
return x+1;
}
void decantor(int x,int *a){
vector<int> v;
for(int i=0;i<9;i++) v.push_back(i);
for(int i=0;i<9;i++){
int r=x%fac[9-i-1];
int t=x/fac[9-i-1];
x=r;
sort(v.begin(),v.end());
a[i]=v[t];
v.erase(v.begin()+t);
}
}
void bfs(){
memset(vis,0,sizeof(vis));
for(int i=0;i<8;i++){
temp[i]=i+1;
}
temp[8]=0;
now.pos=8;
now.hash=result;
now.path="";
vis[result]=1;
path[result]="";
q.push(now);
while(!q.empty()){
now=q.front();
q.pop();
for(int i=0;i<4;i++){
int xx=now.pos/3+dir[i][0];
int yy=now.pos%3+dir[i][1];
if(xx>=0&&yy>=0&&xx<=2&&yy<=2){
st=now;
st.pos=xx*3+yy;
decantor(now.hash-1,temp);
swap(temp[now.pos],temp[st.pos]);
st.hash=cantor(temp);
if(!vis[st.hash]){
vis[st.hash]=1;
st.path=opp[i]+st.path;
q.push(st);
path[st.hash]=st.path;
}
}
}
}
return ;
}
int main(){
bfs();
char x;
while(cin>>x){
if(x=='x'){
//now.pos=0;
temp[0]=0;
}else{
temp[0]=x-'0';
}
for(int i=1;i<9;i++){
cin>>x;
if(x=='x'){
//now.pos=i;
temp[i]=0;
}else{
temp[i]=x-'0';
}
}
now.hash=cantor(temp);
if(!vis[now.hash]) cout<<"unsolvable\n";
else cout<<path[now.hash]<<"\n";
}
return 0;
}