http://acm.hdu.edu.cn/showproblem.php?pid=1043
今天又把八数码拿出来写了一遍,记得上次写这题是暑假集训的时候,那时POJ上能过,但是拿到HDU上交就TLE啊,只能说明POJ上,这题的数据太水了, ~~~ 这次写主要也是为了学下A*算法吧。 不过我写的A* 在HDU上还是要1000+ms,囧。。 应该是启发函数没有处理好吧。。
算法:A* , BFS, IDA*
BFS代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define MAX 363000
using namespace std;
char ch[30];
bool vis[MAX];
int d_r[4] = {1,-1,0,0} ; //方向数组
int d_c[4] = {0,0,1,-1} ;
bool success ;
char path[4] = {'d','u','r','l'} ; //方向数组
int fac[11] = {1,1,2,6,24,120,720,5040,40320,362880} ;
struct Node{
int num[11]; //状态
int ka; //该状态对应的KT值
}start,goal; //状态结构体
queue<Node> q ;
struct Node2{
int pre; //状态(KT值唯一标示)的前一个状态
int way ; //到达该状态的方式
}state[MAX];
//求任意一个排列的KT展开
inline int KT(int n,int num[])
{
int i,j,t,sum=0 ;
for(i=1;i<=n;i++)
{
t = 0 ;
for(j=i+1;j<=n;j++)
if(num[j] < num[i]) t++;
sum += t *fac[n-i] ;
}
return sum + 1 ;
}
inline int recode(char s)
{
if(s == 'x') return 0;
else return s - '0' ;
}
void find(int way,Node now)
{
int num[5][5],i,j,t,pos_r,pos_c;
Node a ;
for(i=1;i<=3;i++)
{
for(j=1;j<=3;j++)
{
num[i][j] = now.num[(i-1)*3+j];
if(num[i][j] == 9)
{
pos_r = i ; pos_c = j ;
}
}
}
int new_r = pos_r + d_r[way] ;
int new_c = pos_c + d_c[way] ;
if(new_r>=1 && new_r<=3 && new_c>=1 && new_c<=3)
{
int temp = num[pos_r][pos_c] ;
num[pos_r][pos_c] = num[new_r][new_c] ;
num[new_r][new_c] = temp ;
t= 1 ;
for(i=1;i<=3;i++)
for(j=1;j<=3;j++)
a.num[t++] = num[i][j] ;
a.ka = KT(9,a.num);
if(!vis[a.ka])
{
q.push(a);
vis[a.ka] = true;
state[a.ka].pre = now.ka ;
state[a.ka].way = way ;
if(a.ka == goal.ka)
{
success = true ;
}
}
}
}
void PRINT(int ka) //打印路径
{
int pre_ka = state[ka].pre ;
if(pre_ka == -1) return ;
PRINT(pre_ka);
printf("%c",path[state[ka].way]);
}
int BFS(Node start)
{
int i,j;
Node now ;
while(!q.empty()) q.pop();
memset(vis,false ,sizeof(vis));
vis[start.ka] = true;
q.push(start);
success = false ;
state[start.ka].pre = -1 ;
state[start.ka].way = 0 ;
while(!q.empty())
{
now = q.front(); q.pop();
for(i=0;i<4;i++)
{
find(i,now);
if(success)
break ;
}
if(success)
break;
}
if(success)
PRINT(goal.ka);
else
printf("unsolvable\n");
}
int main()
{
int i,j,num,t,pos_x;
//freopen("1in.txt","r",stdin);
//freopen("1out.txt","w",stdout);
for(i=1;i<=9;i++)
{
goal.num[i] = i ;
}
goal.ka = 1 ;
while(gets(ch)!=NULL)
{
t = 1 ;
for(i=0;ch[i]!=0;i++)
{
if(ch[i] == ' ') continue ;
start.num[t] = recode(ch[i]) ;
if(start.num[t] == 0)
{
start.num[t] = 9 ;
}
t++ ;
}
start.ka = KT(9,start.num);
BFS(start); //广搜
}
return 0;
}
A*算法:这题严格来说不是用A*过的,而是用了一个is_ok()函数过的。。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cstdlib>
#include<cmath>
#define MAX 363000
using namespace std;
int d_r[4] = {0,0,-1,1} ; //方向数组
int d_c[4] = {1,-1,0,0} ;
char path[4] = {'r','l','u','d'} ; //方向数组
int fac[11] = {1,1,2,6,24,120,720,5040,40320,362880} ;
int d_x[10] = {0,1,1,1,2,2,2,3,3,3} ;
int d_y[10] = {0,1,2,3,1,2,3,1,2,3} ;
int vis[MAX] ;
char ans[MAX] ;
struct Node{
int num[11]; //状态
int ka,space; //该状态对应的KT值
int h,g ;
friend bool operator < (const Node & x,const Node & y)
{
return (x.h+x.g) > (y.h+y.g) ;
}
}start,a,now; //状态结构体
priority_queue<Node> q ;
struct Node2{
int pre; //状态(KT值唯一标示)的前一个状态
int way ; //到达该状态的方式
}state[MAX];
//求任意一个排列的KT展开
inline int KT(int n,int num[])
{
int i,j,t,sum=0 ;
for(i=1;i<=n;i++)
{
t = 0 ;
for(j=i+1;j<=n;j++)
if(num[j] < num[i]) t++;
sum += t * fac[n-i] ;
}
return sum ;
}
inline int cal_h(int num[])
{
int h = 0;
for(int i=1;i<=3;i++)
{
for(int j=1;j<=3;j++)
{
int Num = num[(i-1)*3+j] ;
h += abs(i - d_x[Num])+abs(j-d_y[Num]) ;
}
}
return h;
}
inline void swap(int &a, int &b)
{
int temp = a; a = b ; b = temp ;
}
void PRINT(int ka) //打印路径
{
int pre_ka = ka ,t=0;
while(state[pre_ka].way != -1)
{
t++;
ans[t] = path[state[pre_ka].way] ;
pre_ka = state[pre_ka].pre ;
}
for(int j=t;j>=1;j--)
{
printf("%c",ans[j]);
}
printf("\n");
}
void A_star(Node start)
{
int i,j ,temp,pos_r,pos_c,new_r,new_c;
start.ka = KT(9,start.num) ;
start.g = 0 ;
start.h = cal_h(start.num) ;
while(!q.empty()) q.pop();
memset(vis,0,sizeof(vis)); //0:未访问,1:已访问结点;
vis[start.ka] = 1 ;
q.push(start);
state[start.ka].pre = -1 ;
state[start.ka].way = -1 ;
while(!q.empty())
{
now = q.top(); q.pop();
if(now.ka == 0)
{
PRINT(0) ;
return ;
}
pos_r = (now.space-1)/3 + 1 ;
pos_c = (now.space-1)%3 + 1 ;
for(i=0;i<4;i++)
{
temp = now.space ;
new_r = pos_r + d_r[i] ;
new_c = pos_c + d_c[i] ;
a = now ;
if(new_r<1 || new_r>3 || new_c<1 || new_c>3) continue ;
a.space = (new_r-1)*3 + new_c ;
swap(a.num[a.space],a.num[temp]) ;
a.ka = KT(9,a.num);
if(vis[a.ka]==0)
{
a.g = now.g + 1 ;
a.h = cal_h(a.num) ;
q.push(a);
vis[a.ka] = 1;
state[a.ka].pre = now.ka ;
state[a.ka].way = i ;
}
}
}
printf("unsolvable\n");
}
bool is_ok(int num[])
{
int sum = 0 ;
int num1[11] ,t=1;
for(int i=1;i<=9;i++)
{
if(num[i]!=9)
{
num1[t++] = num[i] ;
}
}
for(int i=1;i<=8;i++)
{
for(int j=1;j<i;j++)
{
if(num1[j]>num1[i]) sum++;
}
}
if(sum%2==0) return true;
else return false ;
}
int main()
{
int i,j,num,t,pos_x;
char ch[5];
while(cin>>ch[1]>>ch[2]>>ch[3])
{
for(i=1;i<=3;i++)
{
if(ch[i] == 'x')
{
start.num[i] = 9 ;
start.space = i;
}
else
start.num[i] = ch[i] - '0' ;
}
for(i=4;i<=9;i++)
{
cin>>ch[0] ;
if(ch[0] == 'x')
{
start.num[i] = 9 ;
start.space = i ;
}
else
start.num[i] = ch[0] - '0' ;
}
if(is_ok(start.num))
A_star(start); //广搜
else
printf("unsolvable\n");
}
return 0;
}