版权声明:那个,最起码帮我加点人气吧,署个名总行吧 https://blog.csdn.net/qq_41670466/article/details/84381615
题意是给你两个八数码,让你输出从第一个八数码到第二个八数码的最短路径,且要求该路径也是最短路径下的字典序最小的路径。
思路:我一开始以为只是简单的在结构体判定一下,让其按照字典序最小的顺序去寻路,后来发现这样做的后果是路径不是最小,嗯。于是就上网查博客,然后就学会了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;
}