八數碼難題(啟發式搜尋)
八數碼難題---啟發式搜素
1.啟發式搜尋:
特點:重排OPEN表,選擇最有希望的節點加以擴充套件
種類:有序搜尋(A演算法)、A*演算法等
2.估價函式
用來估算節點處於最佳求解路徑上的希望程度的函式
f(n) = g(n) + h(n)
n——搜尋圖中的某個當前被擴充套件的節點;
f(n) ——從初始狀態節點s, 經由節點n到達目標節點ng,估計的最小路徑代價;
g(n) ——從s到n 的實際路徑代價;
h(n)——從n到ng,估計的最小路徑代價。
八數碼難題估價函式:f(n)=d(n)+w(n)
其中:d(n)為n的深度 w(n)為不在位的棋子數
3.有序搜尋:
選擇OPEN表上具有最小f值的節點作為下一個要擴充套件的節點。
八數碼難題使用全域性擇優搜尋:
選擇OPEN表上具有最小f值的節點作為下一個要擴充套件的節點,即總是選擇最有希望的節點作為下一個要擴充套件的節點。
在八數碼難題中, 令估價函式
f(n)=d(n)+p(n)
啟發函式h(n)=p(n),p(n)為不在位的棋子與其目標位置的距離之和,則有p(n)≤h*(n),滿足A*演算法的限制條件。
w(n)——不在位的棋子數,不夠貼切,錯誤選用節點加以擴充套件。
p(n)——更接近於h*(n)的h(n),其值是節點n與目標狀態節點相比較,每個錯位棋子在假設不受阻攔的情況下,移動到目標狀態相應位置所需走步的總和。
p(n)比w(n)更接近於h*(n),因為p(n)不僅考慮了錯位因素,還考慮了錯位的距離(移動次數)
資料結構的建立:由於open,close表常設計刪除增加節點的操作,故使用單鏈表最好
open表儲存生成的節點且未被處理的節點,處理過的節點取出放入close表
close表儲存處理過的節點
status表儲存所有生成的節點
採用全域性擇優的思想
java程式碼如下:package 八數碼難題; import java.util.Collections; import java.util.LinkedList; import java.util.List; public class Main { static int f[][]=new int[3][3]; static int e[][]=new int[3][3]; static int p=0; static int dir[][]={{0,1},{1,0},{0,-1},{-1,0}}; static List<node>openlist=new LinkedList<node>(); static List<node>closelist=new LinkedList<node>(); static int d=0; static List<node>status=new LinkedList<node>(); public static void main(String[] args) { // TODO Auto-generated method stub String str1;//初始狀態 String str2;//目標狀態 str1="2831647.5";//空格用.表示 str2="1238.4765"; for(int i=0;i<str1.length();i++){ f[i/3][i-i/3*3]=str1.charAt(i)=='.'?0:str1.charAt(i)-'0'; e[i/3][i-i/3*3]=str2.charAt(i)=='.'?0:str2.charAt(i)-'0'; } node f1=new node(f,d,e); openlist.add(f1); status.add(f1); Search();//尋找最短路徑 toPrint();//輸出狀態空間 } public static boolean check(int x,int y){ if(x<0||x>=3||y<0||y>=3){ return false; } return true; } public static boolean contains(List<node> list,int a[][]){ int flag=0; int a1[][] = new int[3][3]; for(int i=0;i<list.size();i++){ flag=0; for(int j=0;j<3;j++){ a1[j]=list.get(i).a[j].clone(); for(int k=0;k<3;k++){ if(a1[j][k]==a[j][k]){ flag++; } } } if(flag==9) return false; } return true; } //輸出狀態空間 public static void toPrint(){ int a[][]; System.out.println(); System.out.println("========狀態空間大小為:"+status.size()+"-----"); int k1=0,i=0; while(i<status.size()){ a=status.get(i).a; System.out.println("---------------"); for(int j=0;j<3;j++){ for(int k=0;k<3;k++){ System.out.print(a[j][k]+" "); } System.out.println(); } i++; } } public static void Search(){ hnode ehn=new hnode(e); while(!openlist.isEmpty()){ int at[][]=new int[3][3]; int min=0; for(int i=0;i<openlist.size();i++){ if(openlist.get(i).f<openlist.get(min).f){ min=i; } } node n=null; n=openlist.remove(min); closelist.add(n); for(int i=0;i<3;i++){ at[i]=n.a[i].clone(); } int x = 0,y = 0; for(int i=0;i<3;i++){ for(int j=0;j<3;j++){ if(at[i][j]==p){ x=i;y=j;//記錄空格在棋盤中的位置(原) break; } } } for(int i=0;i<4;i++){ int nx,ny,t; nx=x+dir[i][0];//空格移動的位置(現) ny=y+dir[i][1]; if(check(nx,ny)){ t=at[nx][ny]; at[nx][ny]=at[x][y]; at[x][y]=t; d=n.h+1; hnode thn=new hnode(at); node tn=new node(at,d,e); if(thn.equals(ehn)){ //找到最短路徑 status.add(tn); closelist.add(tn); toOutput(); return; } if(contains(openlist,at)&&contains(closelist,at)){ openlist.add(tn); status.add(tn); } t=at[nx][ny]; at[nx][ny]=at[x][y]; at[x][y]=t; } } } return; } public static void toOutput(){ System.out.println("====移動路徑如下===="); System.out.println("所需步數為:"+d); for(int i=0;i<closelist.size();i++){ int a[][]=closelist.get(i).a; System.out.println("----------------------"); for(int j=0;j<3;j++){ for(int k=0;k<3;k++){ System.out.print(a[j][k]+" "); } System.out.println(); } } } } class hnode{ //hash用於hashSet int hash; public hnode(){ } public hnode(int a[][]){ int hc=0; for(int i=0;i<3;i++){ for(int j=0;j<3;j++){ hc*=10; hc+=a[i][j]; } } this.hash=hc; } public boolean equals(Object object){ hnode thn=(hnode)object; return thn.hash==hash; } @Override public int hashCode(){ return hash; } } class node{ int a[][];//九宮格的狀態 int h;//深度 int f;//從初始狀態節點s, 經由節點n到達目標節點ng,估計的最小路徑代價 int p;//不在位的棋子與其目標位置的距離之和 public node(int [][]a,int h,int [][]e){ this.a=new int[3][]; for(int i=0;i<3;i++){ this.a[i]=a[i].clone(); } this.h=h; this.p=work(e); this.f=this.h+this.p; } public int work(int e[][]){ int ants=0; for(int i=0;i<3;i++){ for(int j=0;j<3;j++){ if(a[i][j]!=e[i][j]&&a[i][j]!=0){ int r=0,c = 0,flag=0; for(int k=0;k<3;k++){ for(int k1=0;k1<3;k1++){ if(a[i][j]==e[k][k1]){ r=k; c=k1; ants+=Math.abs(r-i); ants+=Math.abs(c-j); flag=1; break; } } if(flag==1) break; } } } } return ants; } }
相關推薦
八數碼難題(啟發式搜尋)
八數碼難題---啟發式搜素1.啟發式搜尋:特點:重排OPEN表,選擇最有希望的節點加以擴充套件種類:有序搜尋(A演算法)、A*演算法等2.估價函式用來估算節點處於最佳求解路徑上的希望程度的函式f(n) = g(n) + h(n) n——搜尋圖中的某個當前被擴充套件的節點;f(
路勁尋找-八數碼問題(判重)
題目:編號為1~8的8個正方形滑塊被擺成3行3列(有一個格子留空)。把一種狀態變成另一種狀態最少移動多少步,到達不了,就輸出-1。 2 6 4 1 3 7
【 HDU1043-經典BFS+康拓展開 八數碼】 (待更)
給定一個序列,由1~8數字和字母x組成,表示的是一個3*3的矩形。每次操作x都能與相鄰的數字交換,問如何操作才能使得序列為{1,2,3,4,5,6,7,8,x}。 //多組資料-需要計算全部路徑後直接輸出 //反向搜尋+打表(離線) #include<iostream&
對於A*演算法的學習(啟發式搜尋)
開篇 這篇文章介紹找最短路徑的一種演算法,它的字我比較喜歡:啟發式搜尋。 標題上寫的是翻譯,只是覺得原文講解的思路很清晰。這篇文章整體構思和原文相差不多,只是有些地方有小的改動, 我想的是用更容易理解的方式、更簡潔的把A*演算法的思想呈現出來。 文章中出現的詞openli
A*演算法解決八數碼問題(C++版本)
八數碼問題定義: 八數碼問題也稱為九宮問題。在3×3的棋盤,擺有八個棋子,每個棋子上標有1至8的某一數字,不同棋子上標的數字不相同。棋盤上還有一個空格,與空格相鄰的棋子可以移到空格中。要求解決的問題是:給出一個初始狀態和一個目標狀態,找出一種從初始轉變成
啟發式搜尋演算法求解八數碼問題(C)
下午看一個遊戲的演算法時看了一下啟發式搜尋演算法,心血來潮跑了一遍很久很久以前寫八數碼的程式(C語言),發現各種問題,後來順著思路整理了一下,貼出來和大家分享一下,直接上程式碼: // // main.c // yunsuan // // Created by ma
P1379 八數碼難題-啟發式搜尋
P1379 八數碼難題 題意:在3×3的棋盤上,擺有八個棋子,每個棋子上標有1至8的某一數字。棋盤中留有一個空格,空格用0來表示。空格周圍的棋子可以移到空格中。要求解的問題是:給出一種初始佈局(初始狀態)和目標佈局(為了使題目簡單,設目標狀態為123804765),找到一種最少
BZOJ1975 SDOI2010魔法豬學院(啟發式搜尋+最短路+堆)
對反圖跑最短路求出每個點到終點的最短路徑,令其為估價函式大力A*,第k次到達某個點即是找到了到達該點的非嚴格第k短路,因為估價函式總是不大於實際值。bzoj可能需要手寫堆。正解是可持久化可並堆,至今是第二次見到這個那當然是不學啦。 #include<iostream> #includ
八數碼問題(劉汝佳版)
state const r++ return 可用 八數碼 ext ear ans 可以采用dfs,對空白點進行操作,然後可用編碼法,哈希表或者集合來標記,代碼如下 #include<iostream> #include<algorithm> #i
HDU-1043:Eight(八數碼+bfs(反向或A*))
題目大意: 給你一個3*3的表,中間有0到8 9個數字。每次你可以使用0和其相鄰的數字交換。使得最後得到一種題目要求的狀態並求出最短路徑。 解題思路: 當然想到的就是bfs求最短路徑,但是要解決幾個問題,用什麼存當前的狀態,map會超時,所以要用hash,hash可
紫書—八數碼問題(BFS)
sed 計算 cstring 藍橋杯 需要 amp 代碼 scan size 八數碼問題 編號為1~8的8個正方形滑塊被擺成3行3列(有一個格子空留),如圖所示。每次可以把與空格相鄰的滑塊(有公共邊才算相鄰)移到空格中,而它原來的位置就稱為了 新的空格。給定
luoguP1379 八數碼難題[IDA*]
-i 感謝 ida har 初始 text can int 夢裏 題目描述 在3×3的棋盤上,擺有八個棋子,每個棋子上標有1至8的某一數字。棋盤中留有一個空格,空格用0來表示。空格周圍的棋子可以移到空格中。要求解的問題是:給出一種初始布局(初始狀態)和目標布局
[ACM] hdu 1251 統計難題 (字典樹)
第一次 stdio.h scrip null 明顯 output 代碼 ane 處理 統計難題 Problem Description Ignatius近期遇到一個難題,老師交給他非常多單詞(僅僅有小寫字母組成,不會有反復的單詞出現),如今老師要他統計出以某
HDU 2045 LELE的RPG難題(遞推)
%d out miss rpg 方式 最終 desc ont != 不容易系列之(3)—— LELE的RPG難題 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768
【基礎練習】【BFS+A*】codevs1225八數碼難題題解
一點 說明 優先 data- push 練習 bool csdn tarjan 題目描寫敘述 Description Yours和zero在研究A*啟示式算法.拿到一道經典的A*問題,可是他們不會做,請你幫他們. 問題描寫敘述 在3×3的棋
洛谷 P1379 八數碼難題
blank swa scan blog times tps dfs cst target 題目描述 在3×3的棋盤上,擺有八個棋子,每個棋子上標有1至8的某一數字。棋盤中留有一個空格,空格用0來表示。空格周圍的棋子可以移到空格中。要求解
luogu P1379 八數碼難題
測試數據 ret %d -c opp ron line star 數碼 題目描述 在3×3的棋盤上,擺有八個棋子,每個棋子上標有1至8的某一數字。棋盤中留有一個空格,空格用0來表示。空格周圍的棋子可以移到空格中。要求解的問
第八次會議(5.6)
需求 5.6 計劃 展示 地圖 基本 人員 做出 修改 人員:劉、宋、房、張(馮因傷病缺席) 地點:地下室 主要議題: 1.分享了上周學習成果 2.討論並解決上周開發問題 3.安排下周開發計劃 會議結果: 1.房展示了對王者榮耀遊戲的人物的屬性比值轉換表,可
八數碼難題
思路 效率 全排列 hash 超時 但是 做到 利用 排列 本題有寫法好幾個寫法,但主要思路是BFS: No。1 采用雙向寬搜,分別從起始態和結束態進行寬搜,暴力判重。如果只進行單向會超時。 No。2 采用hash進行判重,寬搜采用單向就可以AC。 No。3 運用康拓展開進
HDU1251 統計難題(字典樹)
lag != tac NPU math def tput struct bee HDU1251 統計難題 Ignatius最近遇到一個難題,老師交給他很多單詞(只有小寫字母組成,不會有重復的單詞出現),現在老師要他統計出以某個字符串為前綴的單詞數量(單詞本身也是自己的前綴)