题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3567
题意:给你一个八数码的起始和终止状态,让你打印路径,要求字典序最小,长度最短,保证输入数据必有解。
思路:2000ms 200组数据,平均10ms一组数据。用A*的话,可能会tle,而且还不能保证字典序最小。所以直接打表,考虑到起点,终点不定,所以需要映射,比如我把起点564178X23映射成123456X87(即12345678X,将7和X交换位置),然后按照这个映射方法,把终点7568X4123映射成5126X3487,那么起点564178X23到终点7568X4123的路径肯定等于123456X87到5126X3487的路径。所以我们可以提前打表,然后通过映射,直接输出表就好了。 但是考虑到X的位置有九种,每次的位置不定,所以我们需要打九次表,然后根据起始状态的X的位置,选择不同的表,输出。
可以先写这道题:http://acm.hdu.edu.cn/showproblem.php?pid=1043
题解:http://blog.csdn.net/acmlzq/article/details/54427716
代码:
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<cmath>
#include<vector>
#include<map>
#include<stack>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define scanfprint() freopen("input.txt","r",stdin)
#define printfprint() freopen("output.txt","w",stdout)
#define mem(a,b) memset(a,b,sizeof(a))
const int spot=1000+10;
const int edge=100000+10;
const int maxn=362880+10;
const double pi=acos(-1.0);
const int mod=1e9+7;
const double ips=0.000001;
const int c_n=9;
bool c_flag[c_n+10];
int c_a[c_n+10],fact[15]= {0,1,1,2,6,24,120,720,5040,40320,362880},m[11][maxn],num=0,casen=0;
struct stu1
{
int pre; //上一个
char dir; //方向
} memory[11][maxn]; //打表 //第一个下标表示第几个表(几对应的是X所在的位置)
struct stu2
{
int c_v,num,coor; //康拓值,打表的下标,表里的下标
} s,t;
bool flag[maxn]; //
int cantor() //康拓展开 c_a[1]到c_a[n]表示一个全排列,返回的ans表示康拓值(从0开始)
{
mem(c_flag,0);
int i,j,sum=0,ans=0,k;
for(i=1,k=c_n; i<=c_n; i++,k--)
{
sum=0;
for(j=c_a[i]-1; j>=1; j--)
{
if(!c_flag[j])
sum++;
}
c_flag[c_a[i]]=1,ans+=sum*fact[k];
}
return ans;
}
void inverse_cantor(int c_m) //康拓逆展开 传入的m是康拓值(从0开始),最终的c_a[1]到c_a[n]是m对应的排列
{
mem(c_flag,0);
int i,j,k,sum;
for(i=1,k=c_n; i<=c_n; i++,k--)
{
sum=c_m/fact[k]+1;
for(j=1; j<=c_n; j++)
{
if(!c_flag[j])
sum--;
if(!sum)
break;
}
c_a[i]=j,c_flag[j]=1,c_m%=fact[k];
}
}
void bfs(int in)
{
int i,temp;
s.c_v=cantor(),s.num=0,s.coor=in;
flag[s.c_v]=1;
m[in][s.c_v]=0;
queue<stu2>q;
q.push(s);
while(!q.empty())
{dd
s=q.front();
q.pop();
inverse_cantor(s.c_v);
for(i=0; i<4; i++)
{
if(!i) //下
{
if(s.coor<7)
{
swap(c_a[s.coor],c_a[s.coor+3]);
t.c_v=cantor();
if(!flag[t.c_v])
{
t.coor=s.coor+3,t.num=++num;
memory[in][num].dir='d',memory[in][num].pre=s.num;
m[in][t.c_v]=num;
flag[t.c_v]=1;
q.push(t);
}
swap(c_a[s.coor],c_a[s.coor+3]);
}
}
if(i==1) //左
{
if(s.coor!=1&&s.coor!=4&&s.coor!=7)
{
swap(c_a[s.coor],c_a[s.coor-1]);
t.c_v=cantor();
if(!flag[t.c_v])
{
t.coor=s.coor-1,t.num=++num;
memory[in][num].dir='l',memory[in][num].pre=s.num;
m[in][t.c_v]=num;
flag[t.c_v]=1;
q.push(t);
}
swap(c_a[s.coor],c_a[s.coor-1]);
}
}
if(i==2) //右
{
if(s.coor!=3&&s.coor!=6&&s.coor!=9)
{
swap(c_a[s.coor],c_a[s.coor+1]);
t.c_v=cantor();
if(!flag[t.c_v])
{
t.coor=s.coor+1,t.num=++num;
memory[in][num].dir='r',memory[in][num].pre=s.num;
m[in][t.c_v]=num;
flag[t.c_v]=1;
q.push(t);
}
swap(c_a[s.coor],c_a[s.coor+1]);
}
}
if(i==3)//上
{
if(s.coor>3)
{
swap(c_a[s.coor],c_a[s.coor-3]);
t.c_v=cantor();
if(!flag[t.c_v])
{
t.coor=s.coor-3,t.num=++num;
memory[in][num].dir='u',memory[in][num].pre=s.num;
m[in][t.c_v]=num;
flag[t.c_v]=1;
q.push(t);
}
swap(c_a[s.coor],c_a[s.coor-3]);
}
}
}
}
}
void print(int in,int n,int step)
{
if(!n)
{
printf("Case %d: %d\n",++casen,step);
return ;
}
print(in,memory[in][n].pre,step+1);
printf("%c",memory[in][n].dir);
}
void init() //打九张表
{
int i,j,temp;
for(i=1; i<=9; i++)
{
mem(flag,0),num=0;
for(j=1; j<=9; j++)
c_a[j]=j;
swap(c_a[i],c_a[9]);
bfs(i);
}
}
void solve() //先映射
{
int a1[15],a2[15],temp1[15],temp2[15],i,j,sub;
char s1[15],s2[15];
scanf("%s%s",s1+1,s2+1);
for(i=1; i<=9; i++)
{
if(s1[i]=='X')
sub=i,a1[i]=9;
else
a1[i]=s1[i]-'0';
temp1[i]=i;
a2[i]=s2[i]=='X'?9:s2[i]-'0';
}
swap(temp1[sub],temp1[9]);
for(i=1; i<=9; i++)
temp2[a1[i]]=temp1[i];
for(i=1; i<=9; i++)
c_a[i]=temp2[a2[i]];
int ans=cantor();
print(sub,m[sub][ans],0);
puts("");
}
int main()
{
init();
int nn;
scanf("%d",&nn);
while(nn--)
{
solve();
}
}