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...