啟發式搜尋演算法求解八數碼問題(C)
阿新 • • 發佈:2019-02-02
下午看一個遊戲的演算法時看了一下啟發式搜尋演算法,心血來潮跑了一遍很久很久以前寫八數碼的程式(C語言),發現各種問題,後來順著思路整理了一下,貼出來和大家分享一下,直接上程式碼:
// // main.c // yunsuan // // Created by mac on 12-8-7. // Copyright 2012年 __MyCompanyName__. All rights reserved. // #include <stdio.h> #include <stdlib.h> #include <time.h> #define N 3 //數碼組大小 #define Max_Step 50 //最大搜索深度 #define MAX 50 typedef struct node//八數碼結構體 { int form[N][N];//數碼組 int evalue;//評估值 int udirect;//所遮蔽方向,防止往回推到上已狀態,1上2下3左4右 struct node *parent;//父節點 }Graph; Graph *Qu[MAX];//佇列 Graph *St[MAX];//堆疊 /////////列印數碼組 void Print(Graph *The_graph) { int i,j; if(The_graph==NULL) printf("圖為空\n"); else { printf("---------------------\n"); for(i=0;i<N;i++) { printf("|\t"); for(j=0;j<N;j++) { printf("%d\t",The_graph->form[i][j]);//遍歷列印 } printf("\t|\n"); } printf("|\t\t\t差距:%d\t|\n",The_graph->evalue);//差距顯示 printf("---------------------\n"); } } /////////評價函式 int Evaluate(Graph *The_graph,Graph *End_graph) { int valute=0;//差距數 int i,j; for(i=0;i<N;i++) { for(j=0;j<N;j++) { if(The_graph->form[i][j]!=End_graph->form[i][j]) { valute++; } } } The_graph->evalue=valute; return valute; } /////////移動數碼組 Graph *Move(Graph *The_graph,int Direct,int CreatNew_graph) { Graph *New_graph;// int HasGetBlank=0;//是否獲取空格位置 int AbleMove=1;//是否可移動 int i,j,t_i,t_j,x,y; for(i=0;i<N;i++)//獲取空格座標i,j { for(j=0;j<N;j++) { if(The_graph->form[i][j]==0) { HasGetBlank=1; break; } } if(HasGetBlank==1) break; } //printf("空格位置:%d,%d\n",i,j); t_i=i; t_j=j; //移動空格 switch(Direct) { case 1://上 t_i--; if(t_i<0) AbleMove=0; break; case 2://下 t_i++; if(t_i>=N) AbleMove=0; break; case 3://左 t_j--; if(t_j<0) AbleMove=0; break; case 4://右 t_j++; if(t_j>=N) AbleMove=0; break; } if(AbleMove==0)//不能移動則返回原節點 { return The_graph; } if(CreatNew_graph==1) { New_graph=(Graph *)malloc(sizeof(Graph));//生成節點 for(x=0;x<N;x++) { for(y=0;y<N;y++) { New_graph->form[x][y]=The_graph->form[x][y];//複製數碼組 } } } else { New_graph=The_graph; } //移動後 New_graph->form[i][j]=New_graph->form[t_i][t_j]; New_graph->form[t_i][t_j]=0; //printf("移動產生的新圖:\n"); //Print(New_graph); return New_graph; } /////////搜尋函式 Graph *Search(Graph *Begin,Graph *End) { Graph *g1,*g2,*g; int Step=0;//深度 int Direct=0;//方向 int i; int front,rear; front=rear=-1;//佇列初始化 g=NULL; rear++;//入隊 Qu[rear]=Begin; while(rear!=front)//佇列不空 { front++;//出隊 g1=Qu[front]; //printf("開始第%d個圖:\n",front); //Print(g1); for(i=1;i<=4;i++)//分別從四個方向推匯出新子節點 { Direct=i; if(Direct==g1->udirect)//跳過遮蔽方向 continue; g2=Move(g1, Direct, 1);//移動數碼組 if(g2!=g1)//數碼組是否可以移動 { //可以移動 Evaluate(g2, End);//評價新的節點 //printf("開始產生的第%d個圖:\n",i); //Print(g2); if(g2->evalue<=g1->evalue+1) { //是優越節點 g2->parent=g1; //移動空格 switch(Direct)//設定遮蔽方向,防止往回推 { case 1://上 g2->udirect=2; break; case 2://下 g2->udirect=1; break; case 3://左 g2->udirect=4; break; case 4://右 g2->udirect=3; break; } rear++; Qu[rear]=g2;//儲存節點到待處理佇列 if(g2->evalue==0)//為0則搜尋完成 { g=g2; //i=5; break; } } else { free(g2);//拋棄劣質節點 g2=NULL; } } } if(g!=NULL)//為0則搜尋完成 { if(g->evalue==0) { break; } } Step++;//統計深度 if(Step>Max_Step) { break; } } return g; } /////////初始化一個八數碼結構體 Graph *CR_BeginGraph(Graph *The_graph) { srand((unsigned)time(0)); int M=10;//隨機移動步數 int Direct; int i,x,y; Graph *New_graph; New_graph=(Graph *)malloc(sizeof(Graph)); for(x=0;x<N;x++) { for(y=0;y<N;y++) { New_graph->form[x][y]=The_graph->form[x][y]; } } for(i=0;i<M;i++) { Direct=rand()%4+1;//產生1-4隨機數 //printf("Direct:%d\n",Direct); New_graph=Move(New_graph, Direct, 0); //Print(New_graph); } New_graph->evalue=0; New_graph->udirect=0; New_graph->parent=NULL; return New_graph; } int main (int argc, const char * argv[]) { // insert code here... /* Graph Begin_graph={ {{2,8,3},{1,6,4},{0,7,5}},0,0,NULL }; Graph Begin_graph={ {{2,8,3},{1,0,4},{7,6,5}},0,0,NULL }; Graph Begin_graph={ {{2,0,1},{4,6,5},{3,7,8}},0,0,NULL }; */ //目標數碼組 Graph End_graph={ {{1,2,3},{8,0,4},{7,6,5}},0,0,NULL }; //初始數碼組 Graph *Begin_graph; Begin_graph=CR_BeginGraph(&End_graph);//隨機產生初始數碼組 Evaluate(Begin_graph, &End_graph);//對初始的數碼組評價 printf("初始數碼組:\n"); Print(Begin_graph); printf("目標數碼組:\n"); Print(&End_graph); Graph *G,*P; int top=-1; //圖搜尋 G=Search(Begin_graph, &End_graph); //列印 if(G) { //把路徑倒序 P=G; //壓棧 while(P!=NULL) { top++; St[top]=P; P=P->parent; } printf("<<<<<<<<<<<<<<<搜尋結果>>>>>>>>>>>>>>>>\n"); //彈棧列印 while(top>-1) { P=St[top]; top--; Print(P); } printf("<<<<<<<<<<<<<<<<<完成>>>>>>>>>>>>>>>>>>\n"); } else { printf("搜尋不到結果,深度為%d\n",Max_Step); //設計搜尋深度範圍主要是防止佇列記憶體越界 } return 0; }