1. 程式人生 > >八數碼問題的A*演算法實現

八數碼問題的A*演算法實現

問題描述

八數碼問題也稱為九宮問題。在3×3的棋盤,擺有八個棋子,每個棋子上標有1至8的某一數字,不同棋子上標的數字不相同。棋盤上還有一個空格,與空格相鄰的棋子可以移到空格中。要求解決的問題是:給出一個初始狀態和一個目標狀態,找出一種從初始轉變成目標狀態的移動棋子步數最少的移動步驟。

程式碼實現

/*
AIDreamer
2017/5/27
*/
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<queue>
using namespace std; const int MAXNODE=100000; const int INF=999999999; const int MOD=10007; struct NODE { int state; int blank;//blank表示0在state的第幾位數字之後 int f;//估價函式 int g;//從起始節點到目前的步數 int h;//啟發式函式,目前節點和目標節點之間的距離,用歐幾里得距離計算 int pre;//該節點的父親節點 int loc; bool operator < (const
NODE &rhs)const { return f>rhs.f; } }node[MAXNODE]; bool CLOSE[MAXNODE]; int nodecount=0; //hash表用來儲存訪問過的狀態 struct HASH { int state[100];//下標從1開始,儲存狀態 int state_loc[100];//儲存狀態所對應的下標 int cnt; }Hash[MAXNODE]; void Put_into_hash(int x)//將node[x]存到hash表中 { int loc=node[x].state%MOD; Hash[loc].state[++Hash[loc].cnt]=node[x].state; Hash[loc].state[Hash[loc].cnt]=x; } int
Is_in_hash(struct NODE a)//若在hash表中返回狀態在node中的下標,若不在返回-1 { int loc=a.state%MOD; for(int i=1;i<=Hash[loc].cnt;i++) { if(a.state==Hash[loc].state[i])return Hash[loc].state_loc[i]; } return -1; } NODE init_node; NODE target_node; /* 得到起點和終點的state */ void In() { int a[10];//儲存3*3的格子 int state=0; int blank; int ans,t; //得到init_node ans=0; for(int i=0;i<9;i++) { scanf("%d",&t); if(t==0){init_node.blank=i;continue;} ans=ans*10+t; } init_node.state=ans; //得到target_node ans=0; for(int i=0;i<9;i++) { scanf("%d",&t); if(t==0){target_node.blank=i;continue;} ans=ans*10+t; } target_node.state=ans; } int Get_euclidean_distance(struct NODE aa,struct NODE bb) { //先將int型的狀態轉換到陣列中 int a[10]; int b[10]; int a_state=aa.state; int b_state=bb.state; for(int i=8;i>=0;i--) { if(aa.blank==i){a[i]=0;continue;} a[i]=a_state%10; a_state/=10; } for(int i=8;i>=0;i--) { if(bb.blank==i){b[i]=0;continue;} b[i]=b_state%10; b_state/=10; } //計算兩個狀態之間的距離 int sum_dis=0; int t;//臨時變數 for(int i=0;i<9;i++) { for(int j=0;j<9;j++) { if(a[i]==b[j] && a[i]!=0) { t=abs(i-j); sum_dis+=t%3+t/3; } } } return sum_dis; } void Init() { init_node.g=0; init_node.h=Get_euclidean_distance(init_node,target_node); init_node.f=init_node.g+init_node.h; init_node.pre=0; target_node.f=INF; target_node.pre=0; } void Change_state(struct NODE &node,int blank_loc,int num_loc)//改變node的狀態,將狀態中blank_loc和num_loc的值互換 { int s[10]; int node_state=node.state; for(int i=8;i>=0;i--) { if(node.blank==i){s[i]=0;continue;} s[i]=node_state%10; node_state/=10; } s[blank_loc]=s[num_loc]; s[num_loc]=0; node.blank=num_loc; node.state=0; for(int i=0;i<9;i++) { if(s[i]!=0)node.state=node.state*10+s[i]; } return ; } void Exchange_state(struct NODE &node1,struct NODE &node2)//交換node1狀態和node2狀態 { struct NODE temp_node; temp_node=node1; node1=node2; node2=temp_node; } void Print_node(struct NODE x)//將狀態以3*3的形式輸出 { int state=x.state; int blank=x.blank; int s[10]; for(int i=8;i>=0;i--) { if(i==blank){s[i]=0;continue;} s[i]=state%10; state/=10; } for(int i=0;i<9;i++) { cout<<s[i]<<" "; if(i%3==2)cout<<endl; } } void A_Star()//找到最優方案後更新target_node中的pre值 { node[++nodecount]=init_node; node[nodecount].loc=1; priority_queue<NODE> Q; Q.push(node[1]);//將初始狀態入隊 Put_into_hash(1); while(!Q.empty()) { struct NODE x=Q.top(); if(x.state==target_node.state && x.blank==target_node.blank){ target_node=x;break;} Q.pop(); NODE temp=x;//臨時結構體變數 for(int i=0;i<9;i++) { temp=x; if( (abs(temp.blank-i)/3+abs(temp.blank-i)%3) ==1 ) { Change_state(temp,temp.blank,i); //cout<<"after_change: "<<temp.state<<" "<<temp.blank<<endl; temp.g=x.g+1; temp.h=Get_euclidean_distance(temp,target_node); temp.f=temp.g+temp.h; int loc=Is_in_hash(temp); if(loc==-1)//若不在hash表中則加入到hash表 { node[++nodecount]=temp; node[nodecount].loc=nodecount; Put_into_hash(nodecount); node[nodecount].pre=x.loc; Q.push(node[nodecount]); } else { if(CLOSE[loc]!=1)//在OPEN表中 { if(temp.f<node[loc].f) { node[loc].f=temp.f;node[loc].g=temp.g;node[loc].h=temp.h; node[loc].pre=x.loc; } } else //節點在CLOSE表中 { if(temp.f<node[loc].f) { node[loc].f=temp.f;node[loc].g=temp.g;node[loc].h=temp.h; node[loc].pre=x.loc; Q.push(node[loc]);//將該節點加入到OPEN表中 CLOSE[loc]=0; } } } } } CLOSE[x.loc]=1; } } int main() { In(); //Exchange_state(init_node,target_node);//為了方面最後輸出,交換初始和目標狀態 Init(); cout<<"初始狀態: "<<init_node.state<<" 空格位置: "<<init_node.blank<<endl; cout<<"目標狀態: "<<target_node.state<<" 空格位置: "<<target_node.blank<<endl; A_Star(); int loc=target_node.loc; int step=0; while(loc!=0) { cout<<"----------第"<<step++<<"步:----------"<<endl; Print_node(node[loc]); loc=node[loc].pre; } cout<<endl; cout<<"一共需要"<<step-1<<"步!"<<endl; return 0; } /* 1 0 3 7 2 4 6 8 5 1 2 3 8 0 4 7 6 5 */