算法课程设计--A*算法解决特定条件下的最短路径问题

这篇具有很好参考价值的文章主要介绍了算法课程设计--A*算法解决特定条件下的最短路径问题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.算法课设题目

         LOL 峡谷地图最优路径规划

算法课程设计--A*算法解决特定条件下的最短路径问题

       以下问题的计算,按照该地图的基本规则来进行在该地图中分布着各种形状不规则的障碍区域环境。整个地图模型,可以根据需求进行自行简化。

问题一:在任意起点与终点之间,规划一条最短路径。

问题二:当你拥有一个闪现的情况下(只能用一次),规划出从起点到终点的一条最短 路径。

题目要求: 1. 生成障碍环境数据,提取障碍物区域。 2. 实现上述情况下,指定任意起始点到目标点下的最优路径规划算法。 3. 实现结果的可视化展示。

2.解决问题思路

      2.1地图的简化和数据导入

         此题的要求区分障碍物和非障碍物部分,可以将地图转化为由0和1(1表示障碍物部分)组成的像素图,精度要求因人而异,我这里是在piskel在线网站上创建了100×100的像素图(太大精度的绘图容易丢失文件,建议下载该应用离线使用),并用黑色像素格绘画障碍物部分,最后导出为png文件,如下图:

算法课程设计--A*算法解决特定条件下的最短路径问题

         那么如何将此图转化成由0和1组成的二值图呢,我这里使用的是c++中stb_image.h头文件中的函数处理,代码如下


int width, height, channels;
    unsigned char* image = stbi_load("C:\\Users\\M\\Downloads\\New Piskel2.png", &width, &height, &channels, STBI_grey);

vector<vector<char>> map(height,vector<char>(width));
    int threshold = 128;//阈值
    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            map[y][x] = (image[y * width + x] < threshold) ? 1 : 0;//黑色的像素点用数字1表示,白色的像素点用数字0表示
        }
    }

     2.2核心算法

      A*算法解决最短路径问题步骤:

  1. 定义节点距离:为了使用 A* 算法找到最短路径,我们首先需要定义节点距离。节点距离是指从起点到节点的实际距离加上从节点到终点的估计距离。估计距离可以使用启发式函数来计算。

  2. 创建初始节点:从起点开始创建一个初始节点,并将其加入Open列表(待探索列表)中。同时将所有其他节点标记为未探索。

  3. 选择下一个节点:从Open列表中选择具有最小节点距离的节点作为下一个要探索的节点。将该节点从Open列表中移除,并标记为已探索。

  4. 更新相邻节点:对于所选节点的每个相邻节点,检查是否已经在Open或Close列表中。如果未被探索,则将其添加到Open列表中,同时计算节点距离和启发式函数的值。如果已经在Open或Close列表中,则更新该节点的距离值(如果经过当前节点到达它的路径更短)。

  5. 重复步骤3和4,直到找到终点或者Open列表为空。如果找到终点,输出最短路径;否则,无可行解决方案。

       首先构建两个类,用于表示点的信息和调用A*算法处理函数,如下代码所示:

class point
{
public:
	int 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(NULL) {}
};
class Astar
{
public:
	void InitAstar(vector<vector<char>>& _map);//导入地图
	list<point*>getpath(point& startpoint, point& endpoint);
private:
	vector<vector<char>> map;//地图二维数组
	int calf(point* p);//计算f值
	int calg(point* startp, point* np);//计算g值
	int calh(point* endp, point* np);//计算h值
	list<point*> openList; //开启列表
	list<point*> closeList; //关闭列表
	point* getpoint();//得到开启列表中f值最小的点
	point* isInList(list<point*>& l, point* p);//判断点是否在表中
	bool isCanReach(point* p, point *target);//判断点能否到达
	vector<point*>getSurroundPoints(point* p);//得到周围可到达的点
};

关于解决问题二的一些设计:

//全局变量定义
bool onechance ;//是否可以闪现
int judge ;//判断数
//初始化
 onechance = false;//是否可以闪现
    judge = 0;//判断数
//进行一次闪现后禁掉之后闪现的可能
  if (judge == 0 && map[Point->x][Point->y] == 1)
        {
            judge = 1;

        }
        if(judge==1&& map[Point->x][Point->y] == 0)
            onechance = false;
      

以下是具体的函数功能的实现:

          访问私有类型将地图数据导入

void Astar::InitAstar(vector<vector<char>>& _map)
{
    map = _map;
}

        计算f

int Astar::calf(point* p)
{
    return p->g + p->h;
}

       计算g

int Astar::calg(point* startp, point* np)
{
    int parentg = np->parent == NULL ? 0 : np->parent->g;
    int ng = (startp->x - np->x)* (startp->x - np->x) + (startp->y - np->y)* (startp->y - np->y);
    return parentg + ng;
}

     计算h

int Astar::calh(point* endp, point* np)
{
    return (endp->x - np->x) * (endp->x - np->x) + (endp->y - np->y) * (endp->y - np->y);
}

     得到open列表中f值最小的点

      

point* Astar::getpoint()
{
    if (!openList.empty()) {

        auto Point = openList.front();

        for (auto& p : openList)//遍历open表

            if (p->f < Point->f)

                Point = p;

        return Point;

    }
    return NULL;
}

     通过坐标点判断点是否在表中

point* Astar::isInList(list<point*>& l, point* P)
{
    for (auto p : l)

        if (p->x == P->x && p->y == P->y)//通过坐标点判断点是否在表中

            return p;

    return NULL;
}

     判断点是否可到达

bool Astar::isCanReach(point* p, point* target)
{
    if (target->x<0 || target->x>map.size() - 1
        || target->y<0 || target->y>map[0].size() - 1
        || (map[target->x][target->y] == 1&& onechance == false)
        || target->x == p->x && target->y == p->y
        || isInList(closeList, target))//如果点与当前节点重合、超出地图、是障碍物、或者在关闭列表中,返回false

        return false;
    else if (map[target->x][target->y] == 1 &&onechance==true)//为障碍物但是有闪现的条件下可到达
    {
        return true;
    }
    else {

        if (abs(p->x - target->x) + abs(p->y - target->y) == 1)//非斜角可以到达

            return true;

        else {

            //斜对角要判断是否绊住

            if (map[p->x][target->y] == 0 && map[target->x][p->y] == 0)

                return true;

            else

                return false;

        }
    }
}

   访问周围可到达的点

vector<point*> Astar::getSurroundPoints(point* p)
{
    vector<point*> surroundpoints;
    for (int x = p->x - 1; x <= p->x + 1; x++)

        for (int y = p->y - 1; y <= p->y + 1; y++)

            if (isCanReach(p, new point(x, y)))
           
                    surroundpoints.push_back(new point(x, y));
            

    return surroundpoints;
}

       求最短路径

list<point*> Astar::getpath(point& startpoint, point& endpoint)
{
  
    list<point*>path;
    if (map[startpoint.x][startpoint.y] == 1|| map[endpoint.x][endpoint.y] == 1)//防止起点终点设置到障碍物中
        return path;
    openList.push_back(new point(startpoint.x, startpoint.y)); //置入起点

    onechance = false;//是否可以闪现
    judge = 0;//判断数
    while (!openList.empty()) {

        auto Point = getpoint(); //找到F值最小的点

        openList.remove(Point);
        closeList.push_back(Point);
        //判断闪现有无结束
        if (judge == 0 && map[Point->x][Point->y] == 1)
        {
            judge = 1;

        }
        if(judge==1&& map[Point->x][Point->y] == 0)
            onechance = false;
        
            

        // 1. 找到当前周围8个格中可以通过的格子

        auto surroundPoints = getSurroundPoints(Point);

        for (auto& target : surroundPoints) {

            // 2. 对某一个格子,如果它不在开启列表中,加入到开启列表,设置当前格为其父节点,计算F G H

            if (!isInList(openList, target)) {

                target->parent = Point;

                target->g = calg(Point, target);

                target->h = calh( &endpoint, target);

                target->f = calf(target);

                openList.push_back(target);

            }

            // 3. 对某一格子,它在开启列表中,计算G值,如果比原来的大,就什么都不做,否则设置它的父节点为当前点,并更新G和F

            else {

                int tempg = calg(Point, target);

                if (tempg < target->g) {

                    target->parent = Point;

                    target->g = tempg;

                    target->f = calf(target);

                }

            }
      
            point* lastPoint = isInList(openList, &endpoint);
            //终点在open表就将该路径存到一个列中
            if (lastPoint)
            {
                point* ep = lastPoint;
               
                while (ep) {

                    path.push_front(ep);

                    ep = ep->parent;

                }
                openList.clear();

                closeList.clear();

                return path;
            }
        }

    }




    return path;
}

2.3可视化展示

使用c++语言下的QT项目进行实现

相关代码如下:

鼠标点击事件

void LOLDREWING::mousePressEvent(QMouseEvent* event)
{
    // 获取鼠标坐标
    QPoint pos = event->pos();

     //更新状态
    if (!start_pressed_)
    {
        start = pos;
        start_pressed_ = true;
    }
    else {
        end = pos;
        update();
        start_pressed_ =false;
    }


    
  
}

绘图事件

void LOLDREWING::paintEvent(QPaintEvent*event)
{

    QWidget::paintEvent(event);

    

    int width, height, channels;
    unsigned char* image = stbi_load("C:\\Users\\M\\Downloads\\New Piskel2.png", &width, &height, &channels, STBI_grey);

    // 转化为二维数组
    vector<vector<char>> map(height, vector<char>(width));
    int threshold = 128;//阈值
    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            map[y][x] = (image[y * width + x] < threshold) ? 1 : 0; //黑色的像素点用数字1表示,白色的像素点用数字0表示
        }
    }

 //地图可视化
    QPainter painter(this);
    painter.setPen(Qt::NoPen);
    painter.setBrush(QBrush(Qt::black));
    for (int i = 0; i < map.size(); ++i) {
        for (int j = 0; j < map[0].size(); ++j) {
            if (map[i][j] == 1) {
                painter.drawRect(j  * 10, i  * 10, 10, 10);//扩大十倍
            }
        }
    }

    Astar astar;

    astar.InitAstar(map);

    //设置起点和结束点


    point O( start.y() / 10, start.x() / 10);

    point P(end.y() / 10, end.x() / 10);

    //A*算法找寻路径

    list<point*> path = astar.getpath(O, P);
    
 
    if (path.size())
        for (const auto i : path)
        {
            painter.setBrush(QColor(255,0,0));
            painter.drawRect(10 * i->y, 10 * i->x,10,10);
        }

    if (!start_pressed_)
    {
        painter.setPen(QColor(0, 255, 0));
        painter.drawLine(start, end);
    }
    // 释放资源
    stbi_image_free(image);
 }

3.代码实现展示

   问题一:

算法课程设计--A*算法解决特定条件下的最短路径问题

   问题二:

     只需将是否可以闪现的bool类型的值改为true即可

   onechance = true;//是否可以闪现

   闪现的使用节省了很多路程

 

4.课设完成遇到的问题和心得体验

    4.1课设解决途中遇到的问题

        图像文件和QT绘图的x-y坐标系和二维数组的表示是相反的,硬是因为这个给我拖了一天进度,我就说怎么好多路径肆无忌惮地穿墙呢

      4.2课设完成心得

         对我来说使用c++解决具体问题还是第一次(本人也是c++语言初学者),从代码中可见我仅仅用到了c++和QT中一些最基础的用法,同时解决这个问题并没有花费我太多时间(大概五六天),一是由于上学期的人工智能课程已经介绍了A*算法的用途和具体原理,导致我能很快地上手解决,其次该问题已经很成熟,网上由许多的大佬讲解并进行借鉴

        

           最后提供完全代码文件以供实验:阿里云盘分享文章来源地址https://www.toymoban.com/news/detail-495132.html

到了这里,关于算法课程设计--A*算法解决特定条件下的最短路径问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 实验六 基于 Dijsktra 算法的最短路径求解

    实验六 基于Dijsktra算法的最短路径求解 一、实验目的 1.掌握图的邻接矩阵表示法,掌握采用邻接矩阵表示法创建图的算法。 2.掌握求解最短路径的 Dijsktra 算法。 二、实验内容 一张地图包括 n 个城市,假设城市间有 m 条路径(有向图),每条路径的长度 已知。给定地图的一个起

    2024年01月18日
    浏览(43)
  • 使用Lambda获取List对象中某一个属性以及获取特定条件下的属性对象

    使用Lambda表达式需要jdk1.8以上的环境 如下所示

    2024年02月15日
    浏览(36)
  • DS图—图的最短路径(无框架)迪杰斯特拉算法

    目录 题目描述 AC代码 题目描述 给出一个图的邻接矩阵,输入顶点v,用迪杰斯特拉算法求顶点v到其它顶点的最短路径。 输入 第一行输入t,表示有t个测试实例 第二行输入顶点数n和n个顶点信息 第三行起,每行输入邻接矩阵的一行,以此类推输入n行 第i个结点与其它结点如果

    2023年04月08日
    浏览(29)
  • Dijkstra算法——单源最短路径(指定一个节点(源点)到其余各个顶点的最短路径)

    国庆期间,小明打算从1号城市出发,在五天假期中分别去往不同的城市(2,3,4,5,6)旅游,为减轻负担,他想要知道1号城市到各个城市之间的最短距离。 现在需要设计一种算法求得源点到任意一个城市之间的最短路径。该问题的求解也被称为“单源最短路径”。 在所有

    2024年02月03日
    浏览(44)
  • 数据结构实验任务六 :基于 Dijsktra 算法的最短路径求解

    本次代码为实验六:基于 Dijsktra 算法的最短路径求解实现。本实验的重点在于对于Dijsktra算法的理解。有关Dijsktra的资料可以参考有关博文: 图论:Dijkstra算法——最详细的分析,图文并茂,一次看懂!-CSDN博客 以下附上实现代码: 以上代码仅供参考,欢迎交流。

    2024年02月04日
    浏览(37)
  • 数据结构(12)Dijkstra算法JAVA版:图的最短路径问题

    目录 12.1.概述 12.1.1.无权图的最短路径  12.1.2.带权图的最短路径 1.单源最短路径 2.多源最短路径 12.2.代码实现 无权图的最短路径,即最少步数,使用BFS+贪心算法来求解最短路径,比较好实现,此处不做展开讨论。 有权图的最短路径,不考虑权重为负数的情况,因为权重为负

    2024年02月06日
    浏览(35)
  • C++语法09:迷宫中的最短路径:广度优先搜索算法的应用

    广搜,即广度优先搜索(Breadth-First Search, BFS),是图论和计算机科学中常用的一种算法。它从一个顶点开始,探索所有相邻的顶点,然后对每个相邻的顶点做同样的操作,直到找到目标顶点或遍历完所有顶点。广搜算法在实际应用中具有广泛的用途和诸多好处,本文将详细探

    2024年02月19日
    浏览(37)
  • 详解图的最短路径算法(BFS、Dijkstra、Floyd)(附上图解步骤)

    最短路径分为两种: (1)单源路径:从某顶点出发,到其他全部顶点的最短路径 (2)顶点间的最短路径:任意两个顶点之间的最短路径 最短路径的结果主要有两个方面: (1)顶点之间最短路径的长度 (2)从源顶点到目标顶点的路径 只有边权为 1 时才能用BFS求最短路。

    2024年02月05日
    浏览(38)
  • c语言写邻接矩阵的最短路径的Dijkstra算法(附有详细代码)

    (1) 用dis数组来存储源点1到其他顶点的初始路径,标记1号顶点, 此时dis数组中的值称为最短路径的估计值。 (2) 从dis数组中找出离源起点最近的点2号,以2号顶点为源点进行找最近的顶点。把2号顶点标记,表示已经有最小值。 以2号顶点为源点,看2号顶点有哪些出边,看能不

    2024年02月05日
    浏览(30)
  • Dijkstra算法实现求有向图中一顶点到其余各个顶点的最短路径

    一、文章说明: C++语言实现; 有向图的存储结构为: 邻接矩阵; 这篇文章的代码是我根据B站UP主 懒猫老师 所写的,能成功运行,VS里面显示有很多警告。而且还可能存在有未调试出的BUG,请多多指教。 观看懒猫老师的视频后,才方便理解博主代码,不然可能理解起来会很吃

    2024年02月08日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包