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; }