A-star算法自学

news2024/11/27 14:32:10

搜索过程

广度优先搜索(BFS)算法与Dijsktra算法的结合,可以得出最短的路径。
将地图信息通过划分为方形或者其他多边形格子的方法进行表示,便于利用二维数组存放地图信息,每个格子有可行和不可行两种状态;每个方格用节点的形式表示(节点可以放置在形状内的任何位置 - 在中心或沿边缘),以便于用于任何形状的格子中的情况。
如上图所示,绿色格子为起点,红色格子为终点,蓝色格子为障碍物
如上图所示,绿色格子为起点,红色格子为终点,蓝色格子为障碍物

评价函数

移动代价
横向/纵向移动代价设为 10
对角线移动代价设为14
主要计算三个值F、G及H
F = G + H
F:从初始块经由n个块后到目标块的最小代价估计
G:表示从起点s到点n的实际成本
G(s) = G(s的父节点) + 10或14(横向移动或者纵向移动)
H:表示从节点n到目标T的估算成本(试探法)
利用曼哈顿方法计算: 计算当前方格n通过横向或者纵向移动到T的节点数 * 10
d = |x1 - x2| + |y1 - y2| * 10
欧式距离计算: 计算n与T的欧式距离

步骤(参考)

设置一个 open list(待检查列表) 及 close list(无需检查列表

  1. 从起点开始,将其存入open list中,open list中的方格可能是路径会通过的,也可能是路径不会通过的方格。

  2. 寻找起点周围所有可以到达的节点(相邻节点),忽略障碍方格;并将这些相邻节点存入open list中并且这些节点的父节点均为起点。

  3. 从open list中将起点取出,存入 close list中,如下图所示:![[Pasted image 20230426120659.png]]图中绿色方块为起点,其边框为蓝色,表示该方块已存入close list中,并且其周围的8个方块均在open list中,且指针指向中间的绿色方块,表示父节点为绿色方块

  4. 继续遍历open list中的节点,并重复下述过程。

    1. 计算每个节点的F值,选择F值的节点n作为当前处理的节点
    2. 对于当前节点n,与其相邻的所有节点(b,c,d等)如下操作:
      1. 如果节点b是不可到达(unreachable)或者在close list中,则不进行任务操作
      2. 如果节点c不在open list中,则将其加入open list中,并将当前节点n设为c 的父代,计算节点b的F、G、H值
      3. 若节点d在open list中,则检查节点n到节点d的路径是否更优(若该路径的g值更小,则说明其更优);若该路径更优,则将节点d的父节点(假设为e)设置为当前节点,并重新计算节点e的F、G值
    3. 将节点n存入 close list中
      在这里插入图片描述
  5. 程序运行结束条件(二者满足其一)

    1. 终点在close list中
    2. 无法找到重点,且open list为空
  6. 得到最优路径:从终点开始,每个节点沿着父节点移动,直达到达起点
    在这里插入图片描述

流程图

在这里插入图片描述

代码

A-star.h

#pragma once
#include<vector>
#include<list>

using namespace std;

const int kCost1 = 10; // 横向、纵向移动代价
const int kCost2 = 14; // 对角线移动代价

struct Point
{
	int x, y; // 点坐标,x为横,y为纵坐标
	int F, G, H; // F = G + H
	Point* parent; // 父代坐标
	Point(int _x, int _y) : x(_x), y(_y), F(0), G(0), H(0), parent(nullptr) {} // 初始
};

class Astar
{
public:
	void InitAstar(vector<vector<int>>& _maze);
	list<Point*> GetPath(Point &starPoint, Point &endPoint, bool isIgnoreCorner);
private:
	Point* findPath(Point &startPoint, Point &endPoint, bool isIgnoreCorner);
	vector<Point*> getSurrentPoints(const Point* point, bool isIgnoreCorner) const;
	bool isCanreach(const Point *point, const Point *target, bool isIgnoreCorner) const;  // 判断某点是否可以用于下一步判断
	Point *isInList(const list<Point *> &list, const Point *point) const; // 判断open_list/close_list中是否包含某点
	Point* getLeastFpoint(); // 从open_list中返回F值最小的节点

	// 计算 F G H
	int calG(Point *temp_start, Point *point);
	int calH(Point *point, Point *end);
	int calF(Point *point);

	vector<vector<int>> maze; // 存放地图的二维数组
	list<Point*> openList; // open_list 列表
	list<Point*> closeList; // close_list 列表

};

A-star.cpp

#include "A-star.h"

void Astar::InitAstar(vector<vector<int>>& _maze)
{
	maze = _maze;
}

list<Point*> Astar::GetPath(Point& starPoint, Point& endPoint, bool isIgnoreCorner)
{
	Point* res = findPath(starPoint, endPoint, isIgnoreCorner);
	list<Point*> path;
	// 返回路径
	while (res)
	{
		path.push_back(res);
		res = res->parent;
	}

	// 情况open list和close list
	openList.clear();
	closeList.clear();

	return path;
}

Point* Astar::findPath(Point& startPoint, Point& endPoint, bool isIgnoreCorner)
{
	openList.push_back(new Point(startPoint.x, startPoint.y)); // open_list中存入七点,并开辟一个新的下一个节点
	while (!openList.empty())
	{
		auto curPoint = getLeastFpoint(); // 找到最小F值的节点
		openList.remove(curPoint); // 从open list中将当前节点移出
		closeList.push_back(curPoint); // 将当前节点存入close list中
		// 1.找到当前节点相邻的可以通过的格子
		auto surroundPoints = getSurrentPoints(curPoint, isIgnoreCorner);
		for (auto& target : surroundPoints)
		{
			// 2. 对某一个格子进行判断, 若其不在open list中,则加入到open list中, 并设其为父节点 计算其 F G H值
			if (!isInList(openList, target))
			{
				target->parent = curPoint;
				target->G = calG(curPoint, target);
				target->H = calH(target, &endPoint);
				target->F = calF(target);

				openList.push_back(target);
			}
			// 3. 若其在open list中,则计算其G值并 与当前节点进行比较,若其G值大,则不进行任何操作, 否则设置它的父节点为当前节点,并更新G F 
			else
			{
				int tempG = calG(curPoint, target);
				if (tempG < target->G)
				{
					target->parent = curPoint;
					target->G = tempG;
					target->F = calF(target);
				}
			}
			Point* resPoint = isInList(openList, &endPoint);
			if (resPoint)
				return resPoint;
		}
	}
	return nullptr;
}

vector<Point*> Astar::getSurrentPoints(const Point* point, bool isIgnoreCorner) const
{
	vector<Point*> surroundPoints;
	for (int x = point->x - 1; x <= point->x + 1; ++x)
		for (int y = point->y - 1; y <= point->y; ++y)
			if (isCanreach(point, new Point(x, y), isIgnoreCorner))
				surroundPoints.push_back(new Point(x, y));
	return surroundPoints;
}

bool Astar::isCanreach(const Point* point, const Point* target, bool isIgnoreCorner) const
{
	/*if (target->x < 0 || target->x > maze.size() - 1 || target->y < 0 || target->y > maze[0].size() - 1 || maze[target->x][target->y] == 1 || target->x == point->x && target->y == point->y || isInList(closeList, target))
		return false;*/
	if (target->x<0 || target->x>maze.size() - 1
		|| target->y<0 || target->y>maze[0].size() - 1
		|| maze[target->x][target->y] == 1
		|| target->x == point->x && target->y == point->y
		|| isInList(closeList, target)) //如果点与当前节点重合、超出地图、是障碍物、或者在关闭列表中,返回false
		return false;
	else
	{
		 只有对角线才能进行搜索
		//if (abs(point->x - target->x) + abs(point->y - target->y) == 1)
		//	return true;
		//else
		//{
		//	// 对角线需要判断是否会遇到障碍
		//	if (maze[point->x][target->y] == 0 && maze[target->x][point->y] == 0)
		//		return true;
		//	else
		//		return isIgnoreCorner;
		//}
		return true;
	}
}

// 判断某个节点是否在列表中
Point* Astar::isInList(const list<Point*>& list, const Point* point) const
{
	for (auto p : list)
		if (p->x == point->x && p->y == point->y)
			return p;
	return nullptr;
}

Point* Astar::getLeastFpoint()
{
	if (!openList.empty())
	{
		auto resPoint = openList.front();
		for (auto& point : openList)
		{
			if (point->F < resPoint->F)
			{
				resPoint = point;
			}
		}
		return resPoint;
	}
	return nullptr;
}

int Astar::calG(Point* temp_start, Point* point)
{
	int extraG = (abs(point->x - temp_start->x) + abs(point->y - temp_start->y)) == 1 ? kCost1 : kCost2;
	int parentG = point->parent == nullptr ? 0 : point->parent->G; // 如果为初始点, 则其父节点为空
	return parentG + extraG;
}

int Astar::calH(Point* point, Point* end)
{
	// 根据曼哈顿算法进行计算
	return (abs(point->x - end->x) + abs(point->y - end->y)) * kCost1;

	//return sqrt((double)(end->x - point->x) * (double)(end->x - point->x) + (double)(end->y - point->y) * (double)(end->y - point->y)) * kCost1;
}

int Astar::calF(Point* point)
{
	return point->G + point->H;
}

main.cpp

#include<iostream>
#include "A-star.h"
#include "A-star2.h"

bool InPath(const int &row, const int &col, const list<Point *> &path)
{
	for (const auto& p : path)
	{
		if (row == p->x || col == p->y)
		{
			return true;
		}
	}
	return false;
}

int main()
{
	// 初始化地图,用二维矩阵代表地图,1表示障碍物,0表示可通
	vector<std::vector<int>> map = { {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
									   {1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1},
									   {1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1},
									   {1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1},
									   {1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1},
									   {1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1},
									   {1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1},
									   {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} };

	Astar astar;
	astar.InitAstar(map);

	// 设置起点和目标点
	Point start(1, 1);
	Point end(6, 10);

	// 寻找路径
	list<Point*> path = astar.GetPath(start, end, false);

	// 打印路径
	for (auto& p : path)
	{
		cout << "(" << p->x << ", " << p->y << ")";
	}
	cout << endl;

	for (int row = 0; row < map.size(); ++row) {
		for (int col = 0; col < map[0].size(); ++col) {
			if (InPath(row, col, path)) {
				if (map[row][col] != 0) {
					cout << "e ";
				}
				else {
					cout << "* ";
				}
			}
			else {
				cout << map[row][col] << " ";
			}
		}
		cout << endl;
	}

}

参考链接:
https://www.gamedev.net/reference/articles/article2003.asp
https://blog.csdn.net/A_L_A_N/article/details/81392212
https://zhuanlan.zhihu.com/p/590786438

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/474849.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[Python图像处理] 小波变换执行图像融合

小波变换执行图像融合 图像融合基础使用小波变换执行图像融合图像融合相关链接 图像融合基础 图像融合是将多个输入图像组合到单个输出图像中的过程&#xff0c;输出图像中包含比单个输入图像更好的场景描述。一个好的图像融合方法应当具备以下属性&#xff1a; 它可以保留不…

JavaScript实现用while语句计算1+n的和的代码

以下为输入圆的半径,输出周长、体积和面积实现结果的代码和运行截图 目录 前言 一、实现用while语句计算1n的和 1.1运行流程及思想 1.2代码段 1.3 JavaScript语句代码 1.4运行截图 【附加】用while计算110的和 1.1代码段 1.3 运行截图 前言 1.若有选择&#xff0c;您…

如何为ChatGPT应用程序自定义模型-微调(fine-tuning)

介绍 通过微调&#xff0c;您可以通过提供以下内容从通过 API 提供的模型中获得更多收益&#xff1a; 比提示设计更高质量的结果能够训练比提示所能容纳的更多示例由于提示时间较短&#xff0c;可以节省代币更低的延迟请求 GPT-3 已经对来自开放互联网的大量文本进行了预训练…

Opencv C++图像处理(全)

文章目录 Opencv官方资料BUG集合一、入门基础1.1、头文件说明&#xff1a;#include <opencv2/opencv.hpp>1.2、头文件说明&#xff1a;#include <opencv2/highgui/highgui.hpp>1.3、计算消费时间函数1.3.1、耗时&#xff1a;getTickCount()1.3.2、频率&#xff1a;…

项目管理-团队管理的4个激励理论

冲突和竞争 冲突&#xff1a;是指两个或两个以上的社会单元在目标上互不相容或互相排斥&#xff0c;从而产生心理上的或行为上的矛盾。冲突并不一定是有害的&#xff0c; “一团和气”的集体不一定是一个高效率的集体。对于有害的冲突要设法加以解决或减少&#xff1b;对有益的…

大三生变身AI顾问入职Prada 抢饭碗的AI造出新饭碗

“ChatGPT让我有点焦虑&#xff0c;我长大了还能找到工作吗&#xff1f;”这是一名小学生透过视频表达的担忧&#xff0c;她有点懊恼&#xff0c;“GPT简直无所不能&#xff0c;会画画、编程、写论文、创作音乐......而我们还在学加减乘除。”这段视频让网友直呼&#xff0c;AI…

并发编程基石:管程

大家好&#xff0c;我是易安&#xff01; 如果有人问我学习并发并发编程&#xff0c;最核心的技术点是什么&#xff0c;我一定会告诉他&#xff0c;管程技术。Java语言在1.5之前&#xff0c;提供的唯一的并发原语就是管程&#xff0c;而且1.5之后提供的SDK并发包&#xff0c;也…

Java新提案,最终还是靠近C#了

Java是一门非常优秀的编程语言&#xff0c;特别是生态繁荣&#xff0c;成熟的轮子很多&#xff0c;各种解决方案都有&#xff0c;要开发一个项目&#xff0c;只需把轮子组装&#xff0c;并根据自己的项目&#xff0c;进行自定义修改&#xff0c;可以极大地提升开发效率。 曾经…

构建OVS网络

构建OVS网络 1. 配置虚拟机环境 &#xff08;1&#xff09;配置虚拟机交换机 1 创建一个名为br-xd的虚拟交换机。 # ovs-vsctl add-br br-xd 2 查询虚拟交换机。 # ovs-vsctl show 5a1cd870-fc31-4820-a7f4-b75c19450582 Bridge br-xd Port br-xd …

QT C++入门学习(1) QT Creator安装和使用

Qt官方下载 Qt 官网有一个专门的资源下载网站&#xff0c;所有的开发环境和相关工具都可以从这里下载&#xff0c;具体地址是&#xff1a;http://download.qt.io/ 进入链接后&#xff0c;是一个文件目录&#xff0c;依次进入这个路径&#xff1a;archive/qt/5.12/5.12.9/qt-o…

NXP公司LPC21XX+W25Q128实现外扩Flash

W25Q128FV串行Flash存储器由65536页组成&#xff0c;每一页256字节&#xff0c;总共128Mbit&#xff0c;相当于16M字节的存储空间。一次写入可操作高达256字节&#xff0c;擦除可以按16个页擦除&#xff08;即一个Sector&#xff09;&#xff0c;128个页擦除&#xff08;八个Se…

元宇宙营销策略、玩法与案例

“元宇宙”依旧是当下品牌创新营销的重要形式&#xff0c;从时趣的行业观察来看&#xff0c;大量品牌方都有着元宇宙的营销意向&#xff0c;但在营销落地上存在不同的进度。一个显而易见的事实是&#xff0c;元宇宙不仅仅是一个虚拟的游戏空间&#xff0c;更是一个未来人人都会…

泛型编程 之模板(template)

C另一种编程思想称为 泛型编程&#xff0c;主要利用的技术就是模板 目录 C另一种编程思想称为 泛型编程&#xff0c;主要利用的技术就是模板 一、概念 二、函数模板 1、语法与使用&#xff1a; 2、函数模板注意事项 3、普通函数与函数模板的区别 4、普通函数与函数模板的调用规…

“探究二叉搜索树:从原理到实现“

&#x1f4d6;作者介绍&#xff1a;22级树莓人&#xff08;计算机专业&#xff09;&#xff0c;热爱编程&#xff1c;目前在c&#xff0b;&#xff0b;阶段>——目标Windows&#xff0c;MySQL&#xff0c;Qt&#xff0c;数据结构与算法&#xff0c;Linux&#xff0c;多线程&…

数量形状遗传率及计算方法

数量性状的遗传率/遗传力(heritability) (1)表型值及其方差的分量 1. 表型值及其剖分 某数量性状的表型值就是实际所度量或观察到的数值。表型值受许多外界因素如士壤、肥力、水分、光照、温度等的改变而发生变异&#xff0c;这种变异归因于环境因素。任何一个数量性状的表现…

SentiBank Dector上手指南

​ 官网链接&#xff1a;https://www.ee.columbia.edu/ln/dvmm/vso/download/sentibank.html SentiBank Detector可以抽取图片中的形容词-名词对&#xff0c;之前一直看到&#xff0c;这次复现模型才第一次用到&#xff0c;上手的时候有点手足无措&#xff0c;因为官网在如何使…

傅里叶变换解析

p.s.本文无论是cos还是sin&#xff0c;都统一用“正弦波”(Sine Wave)一词来代表简谐波。 一、什么是频域 从我们出生&#xff0c;我们看到的世界都以时间贯穿&#xff0c;股票的走势、人的身高、汽车的轨迹都会随着时间发生改变。这种以时间作为参照来观察动态世界的方法我们称…

自动驾驶技术的优势、局限性及未来发展趋势

自动驾驶技术是当前汽车行业的热门话题之一。该技术的发展&#xff0c;不仅可以提高车辆的安全性和行驶效率&#xff0c;还可以为人们的出行带来更多便利。但与此同时&#xff0c;自动驾驶技术也存在着许多争议和挑战。接下来从以下四个方面谈一下我对自动驾驶技术的看法。 一…

贝叶斯决策理论

贝叶斯决策理论的相关知识 贝叶斯的思想&#xff1a;顾名思义&#xff0c;贝叶斯决策论是利用概率来进行决策&#xff0c;是概率框架下的方法。贝叶斯决策论是利用概率的不同分类决策与相应的决策代价之间的平衡&#xff0c;核心思想是决策问题可以通过概率的形式来描述。 1.…

数量性状基因座QTL及其作图

数量性状基因座作图原理与步骤 经典的数量遗传分析方法 ->只能分析控制数量性状表现的众多基因的综合遗传效应,无法准确鉴别基因的数目、单个基因在染色体上的位置和遗传效应 (1)数量性状基因座(QTL) Quantitative trait loci: QTL 数量性状位点(基因座) 所谓QTL是指通过…