HDU 1043 八數碼問題 A 搜尋

2021-06-07 17:50:24 字數 1738 閱讀 6746

by---cxlove

第乙個a*搜尋,a*是一種啟發式搜尋,g為已花代價,h為估計的剩餘代價,而a*是根據f=g+h作為估價函式進行排列,也就是優先選擇可能最優的節點進行擴充套件。

對於八數碼問題,以下幾個問題需要知道

判斷有無解問題:根據逆序數直接判斷有無解,對於乙個八數碼,依次排列之後,每次是將空位和相鄰位進行調換,研究後會發現,每次調換,逆序數增幅都為偶數,也就是不改變奇偶性,所以只需要根據初始和目標狀態的逆序數正負判斷即可。

hash問題:根據的是康托展開,具體證明請找網上資料

以及估價函式h:是根據與目標解的曼哈頓距離,也就是每個數字與目標位置的曼哈頓距離之和。

以了以上的基礎,便可以通過a*解決八數碼問題。

對於這題,實驗了下,優先佇列第一關鍵字為f,第二關鍵字為h,耗時2s+,第一關鍵字為f,第二關鍵字為g,耗時1s+,第一關鍵字為h,第二關鍵字為g,耗時450ms左右。在搜尋過程中,加上判斷是否有解,時間變化不大。poj上0ms

#include#include#include#include#include#include#include#include#include#define inf 1<<30

#define eps 1e-7

#define ld long double

#define ll long long

#define maxn 1000000005

using namespace std;

struct node

bool check()

}s,u,v,tt;

int hash[9]=; //hash的權值

int destination=322560; //目標情況的hash值

int vis[400000]; //判斷狀態已遍歷,初始為-1,否則為到達這步的轉向

int pre[400000]; //路徑儲存

int way[4][2]=,,,}; //四個方向

void debug(node tmp)

printf("%d %d\n%d %d\n",tmp.x,tmp.y,tmp.g,tmp.h);

printf("hash=%d\n",tmp.hash);

}int get_hash(node tmp)

return res;

}bool isok(node tmp)

int get_h(node tmp)

void astar()

if(v.hash==destination)

return ;

}} }

}void print()

nxt=pre[nxt];

} for(int i=ans.size()-1;i>=0;i--)

putchar(ans[i]);

puts("");

}int main()

else

s.maze[i][j]=str[k]-'0';

}else

j--;

k++;

}if(!isok(s))

s.hash=get_hash(s);

if(s.hash==destination)

vis[s.hash]=-2;

s.g=0;s.h=get_h(s);

astar();

print();

} return 0;

}

HDU 1043 八數碼問題 A 搜尋

by cxlove 第乙個a 搜尋,a 是一種啟發式搜尋,g為已花代價,h為估計的剩餘代價,而a 是根據f g h作為估價函式進行排列,也就是優先選擇可能最優的節點進行擴充套件。對於八數碼問題,以下幾個問題需要知道 判斷有無解問題 根據逆序數直接判斷有無解,對於乙個八數碼,依次排列之後,每次是將空位...

HDU1043 八數碼問題

include include include using namespace std 通過康托展開來hash 9 有362880 const int maxn 400000 int step maxn int p maxn 2 用於記錄與前面乙個的相對路徑 int d 10 用來統計0到9的階乘 ...

HDU 1043 八數碼問題 雙向BFS

題目鏈結 題意 給你乙個初始狀態,問你能否移動到最終的完成狀態,如果能輸出任意一組解,否則輸出unsolved。思路 乍一看是個bfs,但是狀態過多會tle或者mle,但是除可bfs確實沒得寫了,這時候就要用到雙向bfs了,起點終點同時bfs,判斷相遇,路徑用string 就行了。注意點 正向路徑s...