HDU3567 進階搜尋 IDA*演算法 八數碼【經典】
阿新 • • 發佈:2018-12-02
題意是給你兩個八數碼,讓你輸出從第一個八數碼到第二個八數碼的最短路徑,且要求該路徑也是最短路徑下的字典序最小的路徑。
思路:我一開始以為只是簡單的在結構體判定一下,讓其按照字典序最小的順序去尋路,後來發現這樣做的後果是路徑不是最小,嗯。於是就上網查部落格,然後就學會了A*演算法的升級版IDA A*演算法,在這裡簡單的說一下也加深一下自己的印象:ida演算法是A*演算法的進化版,它捨棄了a*演算法的空間消耗,沒有維護判定點和未判定點的陣列,而是先按照一個限定值,在這個限定值下去查詢,如果在這個限定值下找到解,那麼這個解一定是最優解,如果找不到,那麼擴大限定值,重複,這樣就對空間進行了優化,同時通過迭代加深搜尋的剪枝,在某些題,時間出奇的好。
更加詳細的請:https://blog.csdn.net/urecvbnkuhbh_54245df/article/details/5856756。
程式碼:
#include<iostream> #include<cstdio> #include<queue> #include<algorithm> #include<vector> #include<cstring> #include<stack> using namespace std; typedef long long ll; const int inf = 0x3f3f3f3f; int m[20]; int posgoal[20];//用來儲存第二個八數碼錶裡每個數字的位置。 int dir[4][2] = { {1,0},{0,-1},{0,1},{-1,0} }; int fac[9] = { 1,1,2,6,24,120,720,5040,40320 }; char op[4] = { 'd','l','r','u' };//這也是本題之所以是輸出字典序最小解的原因,因為是dfs的主題框架啊,所以我可以讓它按照字典序的最小的方式去搜,如果有答案,那麼一定符合字典序最小解。 int hash(int s[])//八數碼問題常用的利用康託展開來進行hash表的建立 { int sum = 0; for (int i = 0; i < 9; i++) { int k = 0; for (int j = i + 1; j < 9; j++) if (s[i] > s[j]) k++; sum += k * fac[8 - i]; } return sum+1; } int geth(int s[])//這裡用曼哈頓距離來預估距離(每個數字恢復到第二個八數碼的曼哈頓距離的和) { int dis = 0; for (int i = 0; i < 9; i++) { if (s[i] != 9) { int x = i / 3, y = i % 3; int xx = posgoal[s[i]]/3, yy = posgoal[s[i] ]%3; dis += abs(x - xx) + abs(y - yy); } } return dis; } char path[100]; int cas, nextd; bool idaal(int loc, int depth, int pre, int limit) { int h = geth(m); if (depth + h > limit) { nextd = min(nextd, depth + h); return false; } if (h == 0) { path[depth] = '\0'; printf("Case %d: %d\n", cas, depth); puts(path); return true; } int x = loc / 3, y = loc % 3; for (int i = 0; i < 4; i++) { if (pre + i == 3) continue; int xx = x + dir[i][0]; int yy = y + dir[i][1]; if (xx < 0 || xx >= 3 || yy < 0 || yy >= 3) continue; int temloc = xx * 3 + yy; swap(m[loc], m[temloc]); path[depth] = op[i]; if (idaal(temloc, depth + 1, i, limit)) return true; swap(m[loc], m[temloc]); } return false; } int main() { int t; scanf("%d", &t); char str[50]; for (cas = 1; cas <= t; cas++) { int loc; scanf("%s", str); for (int i = 0; i < 9; i++) { if (str[i] == 'X') m[i] = 9, loc = i; else m[i] = str[i] - '0'; } scanf("%s", str); for (int i = 0; i < 9; i++) { if (str[i] == 'X') posgoal[9] = i; else posgoal[str[i] - '0'] = i; } for (int limit = geth(m);; limit = nextd) { nextd = inf; if (idaal(loc, 0, inf, limit))//如果返回的是false,則擴大limit的值 break; } } //system("pause"); return 0; }