實驗三:A星算法求解8數(shù)碼問題實驗_第1頁
實驗三:A星算法求解8數(shù)碼問題實驗_第2頁
實驗三:A星算法求解8數(shù)碼問題實驗_第3頁
實驗三:A星算法求解8數(shù)碼問題實驗_第4頁
實驗三:A星算法求解8數(shù)碼問題實驗_第5頁
已閱讀5頁,還剩11頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

實驗三:A*算法求解8數(shù)碼問題實驗實驗?zāi)康氖煜ず驼莆諉l(fā)式搜索的定義、估價函數(shù)和算法過程,并利用A*算法求解N數(shù)碼難題,理解求解流程和搜索順序。實驗內(nèi)容八數(shù)碼問題描述所謂八數(shù)碼問題起源于一種游戲:在一個3×3的方陣中放入八個數(shù)碼1、2、3、4、5、6、7、8,其中一個單元格是空的。將任意擺放的數(shù)碼盤(城初始狀態(tài))逐步擺成某個指定的數(shù)碼盤的排列(目標狀態(tài)),如圖1所示圖1八數(shù)碼問題的某個初始狀態(tài)和目標狀態(tài)對于以上問題,我們可以把數(shù)碼的移動等效城空格的移動。如圖1的初始排列,數(shù)碼7右移等于空格左移。那么對于每一個排列,可能的一次數(shù)碼移動最多只有4中,即空格左移、空格右移、空格上移、空格下移。最少有兩種(當空格位于方陣的4個角時)。所以,問題就轉(zhuǎn)換成如何從初始狀態(tài)開始,使空格經(jīng)過最小的移動次數(shù)最后排列成目標狀態(tài)。八數(shù)碼問題的求解算法2.1盲目搜索寬度優(yōu)先搜索算法、深度優(yōu)先搜索算法2.2啟發(fā)式搜索啟發(fā)式搜索算法的基本思想是:定義一個評價函數(shù)f,對當前的搜索狀態(tài)進行評估,找出一個最有希望的節(jié)點來擴展。先定義下面幾個函數(shù)的含義:f*(n)=g*(n)+h*(n)(1)式中g(shù)*(n)表示從初始節(jié)點s到當前節(jié)點n的最短路徑的耗散值;h*(n)表示從當前節(jié)點n到目標節(jié)點g的最短路徑的耗散值,f*(n)表示從初始節(jié)點s經(jīng)過n到目標節(jié)點g的最短路徑的耗散值。評價函數(shù)的形式可定義如(2)式所示:f(n)=g(n)+h(n)(2)其中n是被評價的當前節(jié)點。f(n)、g(n)和h(n)分別表示是對f*(n)、g*(n)和h*(n)3個函數(shù)值的估計值。利用評價函數(shù)f(n)=g(n)+h(n)來排列OPEN表節(jié)點順序的圖搜索算法稱為算法A。在A算法中,如果對所有的x,h(x)<=h*(x)(3)成立,則稱好h(x)為h*(x)的下界,它表示某種偏于保守的估計。采用h*(x)的下界h(x)為啟發(fā)函數(shù)的A算法,稱為A*算法。針對八數(shù)碼問題啟發(fā)函數(shù)設(shè)計如下:f(n)=d(n)+p(n)(4)其中A*算法中的g(n)根據(jù)具體情況設(shè)計為d(n),意為n節(jié)點的深度,而h(n)設(shè)計為把S放入OPEN表,記f=hOPEN=NULL?是失敗擴展BESTNODE,產(chǎn)生其后繼結(jié)點SUCCESSOR選取OPEN表上未設(shè)置過的具有最小f值的節(jié)點BESTNODE,放入CLOSED表BESTNODE是目標節(jié)點建立從SUCCESSOR返回BESTNODE的指針計算g(SUC)=g(BES)+k(BES,SUC)SUC∈OPEN開始g(SUC)<g(OLD)SUC=OLD,把它添加到BESTNDOE的后繼結(jié)點表中重新確定OLD的父輩節(jié)點為BESTNODE,并修正父輩節(jié)點的g值和f值,記下g(OLD)是成功把S放入OPEN表,記f=hOPEN=NULL?是失敗擴展BESTNODE,產(chǎn)生其后繼結(jié)點SUCCESSOR選取OPEN表上未設(shè)置過的具有最小f值的節(jié)點BESTNODE,放入CLOSED表BESTNODE是目標節(jié)點建立從SUCCESSOR返回BESTNODE的指針計算g(SUC)=g(BES)+k(BES,SUC)SUC∈OPEN開始g(SUC)<g(OLD)SUC=OLD,把它添加到BESTNDOE的后繼結(jié)點表中重新確定OLD的父輩節(jié)點為BESTNODE,并修正父輩節(jié)點的g值和f值,記下g(OLD)是成功SUC∈CLOSED把SUCCESSOR放入OPEN表,添進BESTNODE的后裔表計算f值是否是否是否否否圖2A*算法流程圖p(n),意為放錯的數(shù)碼與正確的位置距離之和。由于實際情況中,一個將牌的移動都是單步進行的,沒有交換拍等這樣的操作。所以要把所有的不在位的將牌,移動到各自的目標位置上,至少要移動從他們各自的位置到目標位置的距離和這么多次,所以最有路徑的耗散值不會比該值小,因此該啟發(fā)函數(shù)h(n)滿足A*算法的條件。A*算法流程圖,如圖2A*算法總結(jié)4.1,把起始狀態(tài)添加到開啟列表。4.2,重復(fù)如下工作:a)尋找開啟列表中f值最低的節(jié)點,我們稱它為BESTNOEb)把它切換到關(guān)閉列表中。c)對相鄰的4個節(jié)點中的每一個*如果它不在開啟列表,也不在關(guān)閉列表,把它添加到開啟列表中。把BESTNODE作為這一節(jié)點的父節(jié)點。記錄這一節(jié)點的f和g值*如果它已在開啟或關(guān)閉列表中,用g值為參考檢查新的路徑是否更好。更低的g值意味著更好的路徑。如果這樣,就把這一節(jié)點的父節(jié)點改為BESTNODE,并且重新計算這一節(jié)點的f和g值,如果保持開啟列表的f值排序,改變之后需要重新對開啟列表排序。d)停止把目標節(jié)點添加到關(guān)閉列表,這時候路徑被找到,或者沒有找到路徑,開啟列表已經(jīng)空了,這時候路徑不存在。4.3,保存路徑。從目標節(jié)點開始,沿著每一節(jié)點的父節(jié)點移動直到回到起始節(jié)點。這就是求得的路徑。5、數(shù)據(jù)結(jié)構(gòu)采用結(jié)構(gòu)體來保存八數(shù)碼的狀態(tài)、f和g的值以及該節(jié)點的父節(jié)點;structNode{ints[3][3];//保存八數(shù)碼狀態(tài),0代表空格intf,g;//啟發(fā)函數(shù)中的f和g值structNode*next;structNode*previous;//保存其父節(jié)點};6、實驗結(jié)果,如圖3所示圖3A*算法求解八數(shù)碼問題實驗結(jié)果7、源代碼//-----------------------------------------------------------------------------//代碼:利用A*算法求解八數(shù)碼問題。//八數(shù)碼問題的啟發(fā)函數(shù)設(shè)計為:f(n)=d(n)+p(n),其中A*算法中的g(n)根據(jù)具體情況設(shè)計為d(n),意為n節(jié)點的深度,而h(n)設(shè)計為p(n),意為放錯的數(shù)碼與正確的位置距離之和。//后繼結(jié)點的獲取:數(shù)碼的移動等效為空格的移動。首先判斷空格上下左右的可移動性,其次移動空格獲取后繼結(jié)點。//-----------------------------------------------------------------------------#include<stdio.h>#include<stdlib.h>#include<math.h>//八數(shù)碼狀態(tài)對應(yīng)的節(jié)點結(jié)構(gòu)體structNode{ints[3][3];//保存八數(shù)碼狀態(tài),0代表空格intf,g;//啟發(fā)函數(shù)中的f和g值structNode*next;structNode*previous;//保存其父節(jié)點};intopen_N=0;//記錄Open列表中節(jié)點數(shù)目//八數(shù)碼初始狀態(tài)intinital_s[3][3]={2,8,3,1,6,4,7,0,5};//八數(shù)碼目標狀態(tài)intfinal_s[3][3]={1,2,3,8,0,4,7,6,5};//------------------------------------------------------------------------//添加節(jié)點函數(shù)入口,方法:通過插入排序向指定表添加//------------------------------------------------------------------------voidAdd_Node(structNode*head,structNode*p){structNode*q;if(head->next)//考慮鏈表為空{(diào)q=head->next; if(p->f<head->next->f){//考慮插入的節(jié)點值比鏈表的第一個節(jié)點值小 p->next=head->next; head->next=p; } else{ while(q->next)//考慮插入節(jié)點x,形如a<=x<=b { if((q->f<p->f||q->f==p->f)&&(q->next->f>p->f||q->next->f==p->f)){ p->next=q->next; q->next=p; break; } q=q->next; } if(q->next==NULL)//考慮插入的節(jié)點值比鏈表最后一個元素的值更大 q->next=p; }}elsehead->next=p;}//------------------------------------------------------------------------//刪除節(jié)點函數(shù)入口//------------------------------------------------------------------------voiddel_Node(structNode*head,structNode*p){structNode*q;q=head;while(q->next){ if(q->next==p){ q->next=p->next; p->next=NULL; if(q->next==NULL)return;//free(p); } q=q->next;}}//------------------------------------------------------------------------//判斷兩個數(shù)組是否相等函數(shù)入口//------------------------------------------------------------------------intequal(ints1[3][3],ints2[3][3]){inti,j,flag=0;for(i=0;i<3;i++) for(j=0;j<3;j++) if(s1[i][j]!=s2[i][j]){flag=1;break;}if(!flag) return1;elsereturn0;}//------------------------------------------------------------------------//判斷后繼節(jié)點是否存在于Open或Closed表中函數(shù)入口//------------------------------------------------------------------------intexit_Node(structNode*head,ints[3][3],structNode*Old_Node){structNode*q=head->next;intflag=0;while(q) if(equal(q->s,s)){ flag=1; Old_Node->next=q; return1;} elseq=q->next;if(!flag)return0;}//------------------------------------------------------------------------//計算p(n)的函數(shù)入口//其中p(n)為放錯位的數(shù)碼與其正確的位置之間距離之和//具體方法:放錯位的數(shù)碼與其正確的位置對應(yīng)下標差的絕對值之和//------------------------------------------------------------------------intwrong_sum(ints[3][3]){inti,j,fi,fj,sum=0;for(i=0;i<3;i++) for(j=0;j<3;j++) { for(fi=0;fi<3;fi++) for(fj=0;fj<3;fj++) if((final_s[fi][fj]==s[i][j])){ sum+=fabs(i-fi)+fabs(j-fj); break; } }returnsum;}//------------------------------------------------------------------------//獲取后繼結(jié)點函數(shù)入口//檢查空格每種移動的合法性,如果合法則移動空格得到后繼結(jié)點//------------------------------------------------------------------------intget_successor(structNode*BESTNODE,intdirection,structNode*Successor)//擴展BESTNODE,產(chǎn)生其后繼結(jié)點SUCCESSOR{inti,j,i_0,j_0,temp;for(i=0;i<3;i++) for(j=0;j<3;j++) Successor->s[i][j]=BESTNODE->s[i][j];//獲取空格所在位置for(i=0;i<3;i++) for(j=0;j<3;j++) if(BESTNODE->s[i][j]==0){i_0=i;j_0=j;break;}switch(direction){ case0:if((i_0-1)>-1){ temp=Successor->s[i_0][j_0]; Successor->s[i_0][j_0]=Successor->s[i_0-1][j_0]; Successor->s[i_0-1][j_0]=temp; return1; } elsereturn0; case1:if((j_0-1)>-1){ temp=Successor->s[i_0][j_0]; Successor->s[i_0][j_0]=Successor->s[i_0][j_0-1]; Successor->s[i_0][j_0-1]=temp; return1; } elsereturn0; case2:if((j_0+1)<3){ temp=Successor->s[i_0][j_0]; Successor->s[i_0][j_0]=Successor->s[i_0][j_0+1]; Successor->s[i_0][j_0+1]=temp; return1; } elsereturn0; case3:if((i_0+1)<3){ temp=Successor->s[i_0][j_0]; Successor->s[i_0][j_0]=Successor->s[i_0+1][j_0]; Successor->s[i_0+1][j_0]=temp; return1; } elsereturn0; }}//------------------------------------------------------------------------//從OPen表獲取最佳節(jié)點函數(shù)入口//------------------------------------------------------------------------structNode*get_BESTNODE(structNode*Open){returnOpen->next;}//------------------------------------------------------------------------//輸出最佳路徑函數(shù)入口//------------------------------------------------------------------------voidprint_Path(structNode*head){structNode*q,*q1,*p;inti,j,count=1;p=(structNode*)malloc(sizeof(structNode));//通過頭插法變更節(jié)點輸出次序p->previous=NULL;q=head;while(q){q1=q->previous;q->previous=p->previous;p->previous=q;q=q1;}q=p->previous;while(q){if(q==p->previous)printf("八數(shù)碼的初始狀態(tài):\n");elseif(q->previous==NULL)printf("八數(shù)碼的目標狀態(tài):\n");elseprintf("八數(shù)碼的中間態(tài)%d\n",count++);for(i=0;i<3;i++) for(j=0;j<3;j++) { printf("%4d",q->s[i][j]); if(j==2)printf("\n"); }printf("f=%d,g=%d\n\n",q->f,q->g);q=q->previous;}}//------------------------------------------------------------------------//A*子算法入口:處理后繼結(jié)點//------------------------------------------------------------------------voidsub_A_algorithm(structNode*Open,structNode*BESTNODE,structNode*Closed,structNode*Successor){structNode*Old_Node=(structNode*)malloc(sizeof(structNode));Successor->previous=BESTNODE;//建立從successor返回BESTNODE的指針Successor->g=BESTNODE->g+1;//計算后繼結(jié)點的g值//檢查后繼結(jié)點是否已存在于Open和Closed表中,如果存在:該節(jié)點記為old_Node,比較后繼結(jié)點的g值和表中old_Node節(jié)點//g值,前者小代表新的路徑比老路徑更好,將Old_Node的父節(jié)點改為BESTNODE,并修改其f,g值,后者小則什么也不做。//即不存在Open也不存在Closed表則將其加入OPen表,并計算其f值if(exit_Node(Open,Successor->s,Old_Node)){ if(Successor->g<Old_Node->g){ Old_Node->next->previous=BESTNODE;//將Old_Node的父節(jié)點改為BESTNODE Old_Node->next->g=Successor->g;//修改g值 Old_Node->next->f=Old_Node->g+wrong_sum(Old_Node->s);//修改f值 //排序~~~~~~~~~~~~~~~~~~ del_Node(Open,Old_Node); Add_Node(Open,Old_Node); } } elseif(exit_Node(Closed,Successor->s,Old_Node)){if(Successor->g<Old_Node->g){ Old_Node->next->previous=BESTNODE; Old_Node->next->g=Successor->g; Old_Node->next->f=Old_Node->g+wrong_sum(Old_Node->s); //排序~~~~~~~~~~~~~~~~~~ del_Node(Closed,Old_Node); Add_Node(Closed,Old_Node); } } else{ Successor->f=Successor->g+wrong_sum(Successor->s); Add_Node(Open,Successor); open_N++; }}//------------------------------------------------------------------------//A*算法入口//八數(shù)碼問題的啟發(fā)函數(shù)為:f(n)=d(n)+p(n)//其中A*算法中的g(n)根據(jù)具體情況設(shè)計為d(n),意為n節(jié)點的深度,而h(n)設(shè)計為p(n),//意為放錯的數(shù)碼與正確的位置距離之和//------------------------------------------------------------------------voidA_algorithm(structNode*Open,structNode*Closed)//A*算法{inti,j;structNode*BESTNODE,*inital,*Successor;inital=(structNode*)malloc(sizeof(structNode));//初始化起始節(jié)點for(i=0;i<3;i++) for(j=0;j<3;j++) inital->s[i][j]=inital_s[i][j];inital->f=wrong_sum(inital_s);inital->g=0;inital->previous=NULL;inital->next=NULL;Add_Node(Open,inital);//把初始節(jié)點放入OPEN表open_N++;while(1){ if(open_N==0){printf("failure!");return;} else{ BESTNODE=get_BESTNODE(Open);//從OPEN表獲取f值最小的BESTNODE,將其從OPEN表刪除并加入CLOSED表中 del_Node(Open,BESTNODE); open_N--; Add_Node(Closed,BESTNODE); if(equal(BESTNODE->s,final_s)){//判斷BESTNODE是否為目標節(jié)點 printf("success!\n"); print_Path(BESTNODE); return; } //針對八數(shù)碼問題,后繼結(jié)點Successor的擴展方法:空格(二維數(shù)組中的0)上下左右移動, //判斷每種移動的有效性,有效則轉(zhuǎn)向A*子算法處理后繼節(jié)點,否則進行下一種移動else{ Successor=(structNode*)malloc(sizeof(structNode));Successor->next=NULL; if(get_successor(BESTNODE,0,Successor))sub_A_algorithm(Open,BESTNODE,Closed,Succes

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論