知识点-A*搜索

知识点-A*搜索和IDA *

解决问题

​ 最短路径搜索,第k短路

概要

​ 一般我们求最短路径都是用Dijkstra算法,这个算法可以比较快的找到一条最短最短路,但要是看这个算法的搜索范围,可以发现,这个算法对很多不需要的区域也进行了搜索,这就大大降低了它的速率。

​ Dijkstra算法只考虑到每个点的代价,那么我们改为考虑到每个点到终点的预计代价,会怎么样呢?这样的话,路径搜索就只会朝着靠近终点的方向进行扩展,要搜索的点数就大大下降了。但是由于我们只能对代价进行粗略的估计,所以可能会遇到下面这种情形:对于一些U型的障碍物,我们很容易察觉不到不能进入U型口,这样找到的路径就会是先进入U型口,再从里面出来,这样就不是最短路径了。

​ 那么该怎么办呢?解决方法就是接下来要说的A*算法了,这个算法说白了就是将上述两个算法综合了一下,同时考虑每个点到终点的预计代价和到这个点的实际代价,从而吸收了这两个算法的优点,可以搜索较小范围就找到最短路径。

​ A*设定了两个函数,g(n)表示从初始结点到任意结点n的代价,h(n)表示从结点n到目标点的启发式评估代价,当从初始点向目标点移动时,A权衡这两者。每次进行主循环时,它检查f(n)最小的结点n,其中f(n) = g(n) + h(n)。

​ 其中h(n)函数的设定可以控制A*算法的行为:

​ h(n)是0的时候,A*算法变为Dijkstra算法,保证可以找到最短路径

​ 大部分的h(n)比实际代价小或等于的时候,A*保证可以找到最短路径,而且h(n)越小,要搜索的节点越多,速度越慢

​ h(n)很精确的等于实际代价时,A*只会搜索最短路径上的点,而不会对其他点进行扩展,当然这种情况一般是不现实的,因为我们很难对价值进行精确的估计

​ 当h(n)经常性的大于实际代价时,A*算法将无法保证搜到的是最短路径,但它会运行的更快

​ 所以在使用A*算法时,如何选取一个适合的h(n)函数就十分重要

​ 下面记录几种在网格图中常用的h(n)函数:曼哈顿距离、对角线距离(可以在网格中走对角线),欧几里得距离

​ 一些优化:

​ 当存在好几条价值相同的路径时,可能会导致算法的效率降低,可以对h(n)函数添加一个附加值

​ 附加值有很多种方法,目标是使相同的f值被区分开来

​ 1、稍稍改变h的单位,让h*=(1.0+p),其中p选择为一个小于移动一步(step)的最小代价 / 期望的最长 路径长度的值

​ 2、添加一个比较函数,在f值相等的时候,再添加附加值进行比较

​ 3、添加一个附加值,让搜索倾向于从初始点到目标点的连线方向

d x 1 = c u r r e n t . x − g o a l . x ; dx1 = current.x - goal.x; dx1=current.xgoal.x;

d y 1 = c u r r e n t . y − g o a l . y ; dy1 = current.y - goal.y; dy1=current.ygoal.y;

d x 2 = s t a r t . x − g o a l . x ; dx2 = start.x - goal.x; dx2=start.xgoal.x;

d y 2 = s t a r t . y − g o a l . y ; dy2 = start.y - goal.y; dy2=start.ygoal.y;

c r o s s = a b s ( d x 1 ∗ d y 2 − d x 2 ∗ d y 1 ) ; cross = abs(dx1*dy2 - dx2*dy1); cross=abs(dx1dy2dx2dy1);

h e u r i s t i c + = c r o s s ∗ 0.001 heuristic += cross*0.001 heuristic+=cross0.001

​ 求k短路的时候,就是用A搜索从起点到终点的最短路径,当终点第k次被搜到的时候,对应的路径长度就是第k短路,为了加快速度,我们可以在搜索前先把终点到每个点的最短距离求出来作为h函数。
以上内容很多参考了《堪称最好最全的A
算法详解》这篇博客,大家感兴趣的可以去搜一下

而IDA* 的话,就像A* 是BFS的优化一样,IDA*就是对迭代加深的优化,核心仍然是估价函数的计算,所以我把它一起写在这了。它和迭代加深的区别就是原来是深度大于期望深度就退出,变为深度加上估计还需深度大于期望深度就退出

复杂度

? ?

例题

[BZOJ 1085]、[Poj2449]

代码(K短路)

#include <bits/stdc++.h>
using namespace std;
#define MAXN 100005
#define INF 0x7f7f7f7f
struct k_th
{
    struct Node
    {
        int x,f,h;
        Node(){}
        Node(int a,int b,int c) : x(a),f(b),h(c){}
        bool operator < (const Node& rhs) const
        {
            if(h==rhs.h)return f>rhs.f;
            return h>rhs.h;
        }
    };

    struct Edge
    {
        int to,nxt,w;
        Edge(){}
        Edge(int a,int b,int c):to(a),nxt(b),w(c){}
    };

    Edge edges[MAXN],redges[MAXN];
    int n,cnte,rcnte,k;
    int dis[1010],vis[1010],rhead[1010],head[1010];

    void init(int inn,int ink)
    {
        this->n=inn;this->k=ink+1;cnte=rcnte=0;
        memset(head,0,sizeof(head));
    }

    void add_edge(int a,int b,int c)
    {
        edges[++cnte]=Edge(b,head[a],c);head[a]=cnte;
        redges[++rcnte]=Edge(a,rhead[b],c);rhead[b]=rcnte;
    }

    queue<int> q;

    void spfa(int st)
    {
        while(!q.empty())q.pop();
        memset(vis,0,sizeof(vis));
        memset(dis,INF,sizeof(dis));
        q.push(st);
        dis[st]=0;vis[st]=1;
        while(!q.empty())
        {
            int x=q.front();q.pop();vis[x]=0;
            for(int i=rhead[x];i;i=redges[i].nxt)
            {
                if(dis[redges[i].to]>dis[x]+redges[i].w)
                {
                    dis[redges[i].to]=dis[x]+redges[i].w;
                    if(!vis[redges[i].to])
                    {
                        vis[redges[i].to]=1;
                        q.push(redges[i].to);
                    }
                }
            }
        }
    }

    priority_queue<Node> qq;
    int Astar(int st,int ed)
    {
        spfa(ed);
        memset(vis,0,sizeof(vis));
        if(dis[st]==INF)return -1;
        if(st==ed)k++;
        qq.push(Node(st,0,dis[st]));
        while(!qq.empty())
        {
            Node x=qq.top();qq.pop();
            ++vis[x.x];
            if(vis[x.x]>k)continue;
            if(vis[ed]==k)return x.f;
            for( int i=head[x.x];i;i=edges[i].nxt )
            {
                int t1=x.f+edges[i].w;
                int t2=t1+dis[edges[i].to];
                qq.push( Node(edges[i].to,t1,t2) );
            }
        }
        return -1;
    }
}e;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: a*算法是一种常用的路径搜索算法,它可以通过广度优先搜索和启发式搜索来找到最短路径。在pyqt上实现a*算法,首先需要设计界面,并在界面上设置起点和终点,然后根据搜索结果,在界面上画出最短路径。 实现a*算法需要定义节点、相邻节点、起点和终点等。在pyqt上使用QWidget来实现界面,可以使用QPainter类来画线和节点。在实现a*算法时,需要用到优先队列来存储待扩展的节点,同时需要定义两个估价函数:启发式函数和代价函数。 在启发式函数中,可以根据节点和终点之间的距离来估计路径的长度。代价函数则用于计算从起点到当前节点的距离。 在算法实现时,可以用一个字典来存储节点和与之相邻的节点,每次扩展节点时,将其所有相邻节点加入优先队列中,按照估计路径长度从小到大排序,然后依次扩展,记录下最短路径。 最后,在界面上绘制最短路径,我们可以将其表示为一条线段,并在节点上标注代价函数的值。完成了路径的绘制,就可以使用pyqt的show()方法来显示整个界面,实现a*算法的可视化效果。 总之,要在pyqt上实现a*算法,需要使用QWidget、QPainter和优先队列等类和数据结构,同时需要定义启发式函数和代价函数,最后,根据搜索结果在界面上绘制最短路径。 ### 回答2: PyQt是Python下使用的GUI工具库,提供了一个连接Qt和Python的桥梁。A*算法是一种广度优先搜索算法的变种,以最短路径为目标的搜索算法。 要实现连接线算法A*,我们需要使用PyQt中的QGraphicsScene和QGraphicsView,这些类提供了丰富的绘图功能和交互功能。我们还需要创建一个QGraphicsItem代表连接线,该item需要重写paint()方法绘制线条。然后按照A*算法的步骤实现路径搜索: 1. 创建节点列表并初始化起点。 2. 对节点列表进行排序,并将起点加入已搜索节点列表。 3. 将离目标节点最近的未搜索节点作为下一个节点。 4. 对该节点进行路径评估,如果路径短于已有路径,则更新该节点路径。 5. 如此反复执行直到找到目标节点或搜索完未搜索节点。 6. 从目标节点开始反向遍历路径,并标记所经过的连接线。 在实现过程中,我们还需要考虑如何将节点和连接线连接起来,如何存储地图信息以及如何进行路径评估等问题。 总体来说,使用PyQt实现连接线算法A*需要我们熟悉PyQt的绘图和交互功能,并具备A*算法和图形算法相关知识和技能。 ### 回答3: PyQt是一种基于Python语言的GUI框架,可以实现丰富的图形用户界面交互效果。而A*算法是一种广泛应用于图形搜索、路径规划等领域的算法,可以帮助我们找到两个点之间最短路径。 要在PyQt中实现连接线算法A*,需要以下步骤: 1. 定义节点类。节点对象需要保存坐标信息、与其他节点相邻的关系、以及A*算法中的相关信息,比如起点到该节点的距离和预估到目标节点的距离等。 2. 实现A*算法。根据节点之间的关系,利用A*算法算出最短路径。 3. 绘制连接线。在PyQt的绘图控件中,根据节点之间的关系,连接各节点,并高亮显示最短路径。 以上就是用PyQt实现连接线算法A*的简要步骤。当然,具体实现细节还需根据具体的场景和需求进行调整和完善。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Best KeyBoard

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值