A*算法启发式搜索--八数码

真挺有缘分,上个礼拜数学建模无人车自动驾驶,假了一个A算法上去,由于word里面上角标显示的比较小队友就问:A算法是什么?😂
其实当时根本不会,但反正是数学建模又不是编程建模,所以随便抄了抄放了上去,昨天也在看但是没看明白,今天来了解一下A的简单算法应用
A
算法通过下面这个函数来计算每个节点的优先级。
在这里插入图片描述
比如说在最小步数模型中,g(n)就相当于从起点到当前状态的真实值
f(n)就是从当前状态到重点预估值即是启发函数
f(n)的条件就是要小于等于g(n)(当前状态的真实值),这样就能保证在重点第一次出队的时候就是最小值。(可用反证法证明)
对于启发函数f(n)根据不同题目要求写出,满足条件f(n)<=g(n)

八数码

在一个 3×3 的网格中,1∼8 这 8 个数字和一个 X 恰好不重不漏地分布在这 3×3 的网格中。

例如:

1 2 3
X 4 6
7 5 8
在游戏过程中,可以把 X 与其上、下、左、右四个方向之一的数字交换(如果存在)。

我们的目的是通过交换,使得网格变为如下排列(称为正确排列):

1 2 3
4 5 6
7 8 X
例如,示例中图形就可以通过让 X 先后与右、下、右三个方向的数字交换成功得到正确排列。

交换过程如下:

1 2 3 1 2 3 1 2 3 1 2 3
X 4 6 4 X 6 4 5 6 4 5 6
7 5 8 7 5 8 7 X 8 7 8 X
把 X 与上下左右方向数字交换的行动记录为 u、d、l、r。

现在,给你一个初始网格,请你通过最少的移动次数,得到正确排列。

输入格式
输入占一行,将 3×3 的初始网格描绘出来。

例如,如果初始网格如下所示:

1 2 3
x 4 6
7 5 8
则输入为:1 2 3 x 4 6 7 5 8

输出格式
输出占一行,包含一个字符串,表示得到正确排列的完整行动记录。

如果答案不唯一,输出任意一种合法方案即可。

如果不存在解决方案,则输出 unsolvable。

输入样例:
2 3 4 1 5 x 7 6 8
输出样例
ullddrurdllurdruldr

#include<iostream>
#include<algorithm>
#include<unordered_map>
#include<cstring>
#include<queue>
#define x first
#define y second
using namespace std;

typedef pair<int,string> PIS;


int f(string state)
{
	int res = 0;
    for (int i = 0; i < state.size(); i ++ )
        if (state[i] != 'x')
        {
            int t = state[i] - '1';
            res += abs(i / 3 - t / 3) + abs(i % 3 - t % 3);//曼哈顿距离
        }
    return res;
}
string bfs(string start)
{
	int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
	char op[4]={'u','r','d','l'};

	string end ="12345678x";
	unordered_map<string,int>dist;//state状态距离起点距离
	unordered_map<string,pair<string,char>> prev;//记录上一个状态,上一个状态的行走方向
	priority_queue<PIS,vector<PIS>,greater<PIS>> heap;//小根堆,堆顶为最小
	dist[start]=0;
	heap.push({f(start),start});
	while(!heap.empty())
	{
		auto t=heap.top();
		heap.pop();
		string state = t.y;
		if(state==end)break;
		int step=dist[state];
		int x,y;
		for(int i=0;i<state.size();i++)
		{
			if(state[i]=='x')
			{
				x=i/3;
				y=i%3;
				break;
			}
		}
		string source = state;
		for(int i=0;i<4;i++)
		{
			int a=x+dx[i],b=y+dy[i];
			state=source;
			if(a>=0&&a<3&&b>=0&&b<3)
			{
				swap(state[x*3+y],state[a*3+b]);
				if(!dist.count(state)||dist[state]>step+1)
				{
					dist[state]=step+1;
					prev[state]={source,op[i]};
					heap.push({dist[state]+f(state),state});
				}
				//swap(state[x*3+y],state[a*3+y]);
			}
		}
	}
	string res;
    while (end != start)
    {
        res += prev[end].second;
        end = prev[end].first;
    }
    reverse(res.begin(), res.end());
    return res;
}
int main(int argc, char const *argv[])
{
	string start,seq;
	char c;
	while(cin>>c)
	{
		start+=c;
		if(c!='x')seq+=c;
	}
	int cnt =0;
	for(int i=0;i<9;i++)
		for(int j=i;j<9;j++)
			if(seq[i]>seq[j])
				cnt++;
	if(cnt&1)
		cout<<"unsolvable"<<endl;
	else
	{
		cout<<bfs(start)<<endl;
	}
	return 0;
}

其实还是有些不理解,一下子这么多数据结构给我整懵了,再多看看吧

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值