http://acm.hdu.edu.cn/showproblem.php?pid=1043
一个事关人生完不完整得题目,自然就要反复多写几遍才能体会其中的精华咯,哈哈。今天又看到了一个用单广的写法,于是乎觉得很好,就自己又写了一遍,没想到109ms。。 Orz。。 连自己都不敢相信哈!! 神马A*、IDA*,都是浮云啊。
这里简单说思路吧: 从终点开始,预处理出终点能到达的状态(这里终点能达到的状态一定是能达到终点的状态),采用逆向搜索的方法,记录下每种状态达到终点状态的下一个KT值和达到方式,这样在任意读入的一个状态下,只要先判断是否能达,若能达,按照pre数组打出每个方式即可。 没牛的一种思路。。
代码:
/*
HDU 1043 Eight
Tips:单广搜
Runtime : 109ms
*/
#include<stdio.h>
#include<string.h>
#include<queue>
#define MAX 362900
using namespace std;
struct Node{
char maze[4][4] ;
int sx,sy ;
}sta[MAX];
queue<Node> q;
int pre[MAX];
char way[MAX];
bool vis[MAX];
int fac[9] = {1,1,2,6,24,120,720,5040,40320} ;
int dir_x[4] = {0,0,1,-1} ;
int dir_y[4] = {1,-1,0,0} ;
char dir_w[4] = {'l','r','u','d'} ; // !!!这里的方向和上面的方向数组时相反的;
//求一个排列的KT
int get_cat(Node a){
int num[10],index=0;
for(int i=1;i<=3;i++){
for(int j=1;j<=3;j++){
if(a.maze[i][j] == 'x'){
num[index++] = 9 ;
}
else
num[index++] = a.maze[i][j] - '0' ;
}
}
int res = 0 ;
for(int i=0;i<9;i++){
int t= 0 ;
for(int j=i+1;j<9;j++){
if(num[i] > num[j]) t++;
}
res = res + fac[8-i]*t ;
}
return res ;
}
//逆向建立可达状态的路径。
void bfs(){
Node a;
int num = 1 ,cat;
for(int i=1;i<=3;i++){
for(int j=1;j<=3;j++){
if(i==3 && j==3){ a.maze[i][j] = 'x' ;a.sx = i; a.sy = j ; }
else {a.maze[i][j] = num + '0' ; num++ ;}
}
}
while(!q.empty()) q.pop();
q.push(a) ;
memset(pre,-1,sizeof(pre));
memset(vis,false,sizeof(vis));
cat = get_cat(a);
vis[cat] = true ;
pre[cat] = -2 ;
while(!q.empty()){
Node now = q.front(); q.pop();
int s_x = now.sx ,s_y = now.sy ;
for(int i=0;i<4;i++){
Node next = now;
int n_x = s_x + dir_x[i] ;
int n_y = s_y + dir_y[i] ;
if(n_x<1 || n_x>3 || n_y<1 || n_y>3) continue ;
char temp = next.maze[s_x][s_y] ;
next.maze[s_x][s_y] = next.maze[n_x][n_y] ;
next.maze[n_x][n_y] = temp ;
next.sx = n_x ;next.sy = n_y ;
cat = get_cat(next) ;
if(vis[cat]){
continue ;
}
else{
pre[cat] = get_cat(now) ;
way[cat] = dir_w[i] ;
q.push(next) ;
vis[cat] = true ;
}
}
}
}
int main()
{
Node start ;
char ss[3] ;
bfs();
while(scanf("%s",ss)!=EOF){
start.maze[1][1] = ss[0] ;
if(ss[0] == 'x'){
start.sx = 1 ; start.sy = 1 ;
}
scanf("%s",ss); start.maze[1][2] = ss[0] ;
if(ss[0] == 'x'){
start.sx = 1 ; start.sy = 2 ;
}
scanf("%s",ss); start.maze[1][3] = ss[0] ;
if(ss[0] == 'x'){
start.sx = 1 ; start.sy = 3 ;
}
for(int i=2;i<=3;i++){
for(int j=1;j<=3;j++){
scanf("%s",ss);
start.maze[i][j] = ss[0] ;
if(ss[0] == 'x'){
start.sx = i ;start.sy = j ;
}
}
}
int cat = get_cat(start) ;
if(pre[cat] == -1){
printf("unsolvable\n");
}
else if(pre[cat] == -2){
printf("\n");
}
else{
int now_c ,pre_c ;
pre_c = cat ; now_c;
while(pre[pre_c]!=-2){ //打印路径即可。
printf("%c",way[pre_c]);
pre_c = pre[pre_c] ;
}
printf("\n");
}
}
return 0;
}