1. 程式人生 > >HDU3567 進階搜尋 IDA*演算法 八數碼【經典】

HDU3567 進階搜尋 IDA*演算法 八數碼【經典】

題意是給你兩個八數碼,讓你輸出從第一個八數碼到第二個八數碼的最短路徑,且要求該路徑也是最短路徑下的字典序最小的路徑。

思路:我一開始以為只是簡單的在結構體判定一下,讓其按照字典序最小的順序去尋路,後來發現這樣做的後果是路徑不是最小,嗯。於是就上網查部落格,然後就學會了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;
}