题目
给你一个1-8的字符串和一个位置x,如13264578x
代表
1 3 2
6 4 5
7 8 x
要求将状态通过重复x与相邻位置交换过程,将局面复位为
1 2 3
4 5 6
7 8 x
要求在最少步数的情况下,输出路径
x向上走则为u,向下d,向左l,向右r
思路来源
https://www.cnblogs.com/goodness/archive/2010/05/04/1727141.html
http://www.bubuko.com/infodetail-635279.html(八数码的八境界)
题解
令x的位置=9,1-9共用9!=36W种状态,康托展开压进36W数组,
从123456789终态逆向bfs,预处理每个状态的后继状态是什么字母,
注意字母应反向,如cantor(123456789)通过l到达cantor(123456798)
则记pre[cantor(123456798)]=cantor(123456789);ans[cantor(123456798)=l;
在询问的时候沿着pre跳就好了,对于有解的情况不过20步左右
朴素的康托展开O(9*9),乘以36W状态,不会超时
心得
去年10月份的大一作业,现在才补上,
因为这个学了康托展开、IDA*入门和A*入门
后来发现后二者并没什么用,并不怎么会用到
八数码的八境界,我大概只能达到第二三重吧,补上就好了
代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <set>
#include <map>
#include <vector>
#include <stack>
#include <queue>
#include <functional>
const double INF=0x3f3f3f3f;
const int maxn=370005;
const int mod=1e9+7;
const int MOD=998244353;
const double eps=1e-7;
typedef long long ll;
#define vi vector<int>
#define si set<int>
#define pii pair<int,int>
#define pi acos(-1.0)
#define pb push_back
#define mp make_pair
#define lowbit(x) (x&(-x))
#define sci(x) scanf("%d",&(x))
#define scll(x) scanf("%lld",&(x))
#define sclf(x) scanf("%lf",&(x))
#define pri(x) printf("%d",(x))
#define rep(i,j,k) for(int i=j;i<=k;++i)
#define per(i,j,k) for(int i=j;i>=k;--i)
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
int jc[10],Hash[maxn],ans[10],endv;
int dx[]={1,0,-1,0},dy[]={0,1,0,-1};
int pre[maxn];
char res[maxn];
char query[105];
char dir[5]="uldr";//由逆操作,记录(x+dx,y+dy)的反方向
struct node
{
int s[9];//记录每个位置的值
int pos;//记录x的位置,也就是9的位置
int v;//记录hash值
};
queue<node>q;
void init()
{
jc[0]=1;
rep(i,1,9)jc[i]=i*jc[i-1];
}
int cantor(int s[])
{
int sum=0,len=9;
rep(i,0,len-1)
{
int num=0;
rep(j,i+1,len-1)
{
if(s[i]>s[j])num++;//后面有多少个数比s[i]小
}
sum+=num*jc[len-1-i];
}
return sum;
}
bool check(int x,int y)
{
if(x>=0&&x<=2&&y>=0&&y<=2)return 1;
return 0;
}
void bfs()
{
node tmp,now;
rep(i,0,8)tmp.s[i]=i+1;
tmp.pos=8;
tmp.v=cantor(tmp.s);
endv=tmp.v;
q.push(tmp);
while(!q.empty())
{
tmp=q.front();
q.pop();
int x=tmp.pos/3,y=tmp.pos%3;
rep(i,0,3)
{
int xx=x+dx[i],yy=y+dy[i];
if(check(xx,yy))
{
now=tmp;
now.pos=xx*3+yy;
//把(x,y)和(xx,yy)互换
now.s[tmp.pos]=now.s[now.pos];//将原x处置现x数
now.s[now.pos]=9;//将现x数置x
now.v=cantor(now.s);
if(!Hash[now.v])
{
Hash[now.v]=1;
pre[now.v]=tmp.v;
res[now.v]=dir[i];
q.push(now);
}
}
}
}
}
int main()
{
init();
bfs();
while(gets(query))
{
mem(ans,0);
int len=strlen(query);
int sum=0,cnt=0;
rep(i,0,len-1)
{
if(query[i]>='1'&&query[i]<='8')ans[cnt++]=query[i]-'0';
else if(query[i]=='x')ans[cnt++]=9;
}
int t=cantor(ans);
if(Hash[t])
{
for(int i=t;i!=endv;i=pre[i])
putchar(res[i]);
puts("");
}
else puts("unsolvable");
}
return 0;
}