蒟蒻林荫小复习——K短路的A*解法

看标题都知道讲的是什么,但为什么特指是A*关于K短路的解法呢?

因为林荫不会其他的。

能看到这篇博客的估计也都知道K短路和A*分别是什么了吧,下面只介绍一下估价函数

由于林荫并没有经过学术训练,所以一下关于A*的理解均为感性,仅可作为OIer速成知识点时的一点资料,

切莫作为算法学术依据。

先思考一下,对于任意一条K短路,是不是均可写成由一部分最短路和一部分其他路径组成,而且这两部分路径还有且仅有一个公共点。

说明:1.任何一条路径都可以视为由其他到终点的路径和终点到终点的最短路组成

   2.哪怕前面的路径上有环,最短路也一定和其他的路径在环的出点上相连。因为一旦最短路和路径上其他点相交,就代表该最短路上有环,那么这条路径就不是最短路。

好的,下面引入概念:估价函数!

实际上没啥特别的,就一个公式 F(x)=G(x)+H(x),F(x)是该路线的期望花费,G(x)是从起点到当前点的花费,H(x)是当前点到终点的最优花费。

那么,我们在求解的时候是不是有个大致思路了?

K值越小的路径的X点离起点越近(大概就这个意思,也可以认为越接近最短路的路线所使用的最短路越多)

那么我们是否可以考虑先将H处理出来(建反图,求单源最短路),然后维护一个优先队列,队列里面保存一个Pair(F(x)和x点),那么我们每次根据F(x)的值决定下一个执行的点,如果x已经是终点了,就该统计答案统计答案,该返回返回,否则针对x计算出每一个相连接的点to,求出F(to)后压入队列,直到完成K个路径或者发现当前最短的一条路径已经不满足需求。

下面放个代码吧,例题COGS3227

严格来说这个并不算K短路,而是给定特殊限制,求满足条件的路径

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
vector<pair<int,int> > b[1001],fb[1001];
int vis[1001],dis[1001];
int n,m,a1,a2,a3,S,F,ans,MX,T;
void DIJ()
{
    memset(dis,0x3f3f3f3f,sizeof(dis));
    memset(vis,0,sizeof(vis));
    priority_queue<pair<int,int> > q;
    dis[F]=0;
    q.push(make_pair(0,F));
    while(q.size())
    {
        int u=q.top().second;
        q.pop();
        if(vis[u])
            continue;
        vis[u]=1;
        for(int i=0;i<fb[u].size();i++)
        {
            int to=fb[u][i].first;
            if(dis[to]>dis[u]+fb[u][i].second)
            {
                dis[to]=dis[u]+fb[u][i].second;
                q.push(make_pair(-dis[to],to));
            }
        }
    }
}
void ASTAR()
{
    priority_queue<pair<int,int> > q;
    q.push(make_pair(-dis[S],S));
    while(q.size())
    {
        int u=q.top().second;
        int v=q.top().first;
        q.pop();
        int dist=-v-dis[u];//实际上从起点到u的距离
        if(dist>MX)
            continue;
        if(u==F)
        {
            if(dist<=MX)
            {
                ans++;
            }
            else
                return;
        }
        for(int i=0;i<b[u].size();i++)
        {
            int to=b[u][i].first;
            q.push(make_pair(-(dist+b[u][i].second+dis[to]),to));
        }
    }
}
int LINYIN()
{
    ans=0;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        b[i].clear();
        fb[i].clear();
    }
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&a1,&a2,&a3);
        fb[a2].push_back(make_pair(a1,a3));
        b[a1].push_back(make_pair(a2,a3));
    }
    scanf("%d%d",&S,&F);
    DIJ();
    MX=dis[S]+1;
    ASTAR();
    printf("%d\n",ans);
    return 0;
}
int LWH()
{
    freopen("sightseeing.in","r",stdin);
    freopen("sightseeing.out","w",stdout);
    scanf("%d",&T);
    while(T--)
    {
        LINYIN();
    }
    return 0;
}
int MYLOVE=LWH();
int main()
{
    ;
}

完结撒花!!!

原文地址:https://www.cnblogs.com/XLINYIN/p/11828725.html

时间: 2024-10-11 01:19:31

蒟蒻林荫小复习——K短路的A*解法的相关文章

蒟蒻林荫小复习——关于有限制区间元素查询的一些解法

如题:本文主要说明对于区间有限制查询的一些解法(其实就两种) 问题1:给定一个数列,要求查询区间L—R中所有大于等于Va小于等于Vb的元素和 解法: 1.线段树套权值线段树 第一维维护区间,第二维作为权值线段树,维护值域在A—B之间的元素之和 每次查询就从第一维拉到对应区间,然后用Va和Vb确定在权值线段树中的查询范围即可 2.分块 分块数组记为a,对每一个a块都开一个数组b,b数组将a块中元素拷贝后排序,新建c,对于每一个b都求前缀和 这样对于整块而言,用二分确定Va和Vb在b数组中的位置Ia

蒟蒻林荫小复习——带权并查集

实际上很早之前林荫是有这个技能的.(废话!要不直接叫小学习好了) 众所周知,并查集可以用来维护一些元素之间相连的关系(不知道的出门右转幼儿园) 而状态压缩可以使得并查集查询一对元素的关系的速度变快(O1) 状态压缩之后的并查集实际上是一个由fa数组(相当于单向链表)构成的菊花图 那么,如何用并查集来维护元素之间实际的数量关系呢? 先看一个例子: 假定现在有3个小朋友ABC,B比A大3岁,C比B大2岁.对于这个问题,如果用不带状压的并查集进行表示,那么就可以得到一条链.B到A的边权3表示 B比A大

蒟蒻林荫的小复习——主席树

主席树也就是指可持久化线段树,大致思想也就是每次利用之前的重复信息,只为被更新的一部分开辟新点.而且所谓可持久化线段树实际上是指可持久化权值线段树,线段树中每个端点存的是这个端点所代表的树的出现次数. 而在主席树的维护当中对于每个历史版本如果都开一颗新树,那么M将是最终的结局.正确解法则是为每一个改变的点分配编号而未改变的点直接链接到新树上. 下面就来从主席树的两个经典问题来考虑 1:区间第K小问题 传送门 首先分析问题,给出一个序列,每次给定一个封闭区间,求这个封闭区间以内的最小值. 上面我们

图的第k短路

[问题描述] 给你一个有向图,求从1到n的第k短路. [解法] SPFA+A*搜索. 1 A*算法 A*算法在人工智能中是一种典型的启发式搜索算法,启发中的估价是用估价函数表示的: h(n)=f(n)+g(n) 其中f(n)是节点n的估价函数,g(n)表示实际状态空间中从初始节点到n节点的实际代价,h(n)是从n到目标节点最佳路径的估计代价.另外定义h'(n)为n到目标节点最佳路径的实际值.如果h'(n)≥h(n)则如果存在从初始状态走到目标状态的最小代价的解,那么用该估价函数搜索的算法就叫A*

小蒟蒻初次CF滚粗+爆炸记 (Codeforces Round #466 Div.2)

比赛链接:http://codeforces.com/blog/entry/57981 小蒟蒻今天初次在ZCDHJ张大佬的带领下,打了一场CF (张大佬cnblogs链接:https://www.cnblogs.com/ZCDHJ)' 英文完全看不懂,后面几题直接放弃,各位dalao请见谅 T1: 题目链接:http://codeforces.com/contest/940/problem/A 题目大意: 给你一个n个数的集合,要求你删掉若干数,其中最大的差不应该超过d,求最小删除量. (小蒟蒻

最短路 次短路 k短路(k很小)

最短路 luogu 3371 https://www.luogu.org/problemnew/show/P3371 1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <queue> 5 #include <algorithm> 6 using namespace std; 7 const int maxn=1e4+10; 8 9 int dist[m

小蒟蒻的blog美化汇总~

小蒟蒻的第一篇blog,应众多某位dalao要求,决定汇总一下blog的美化(.?∀?)ノ 1.0背景更换 1.1首先选择你喜欢的皮肤~ 1.2然后在网上照一张你喜欢的图片把它存到相册里点开图片左下角有个original image点开它复制一下网址即可 1.3上代码(页面定制) /*simplememory*/ #google_ad_c1, #google_ad_c2 {display:none;} .syntaxhighlighter a, .syntaxhighlighter div, .

关于如何食用Xcode——用mac的小蒟蒻

前言QwQ 对于一只用Mac的小蒟蒻,没有Dev_c++简直太难受了,用在线IDE写代码又没法保存,那么我们怎么办呢? 好在App Store里有这个好东西 所以我们今天来介绍一下 “如何使用Xcode” 0x00 新建文件 Step 1 :打开Xcode 会看到这样的一个界面->  Step 2 :选择中间的"Create a new Xcode project" Step 3 :一定要选macOS下的Command Line Tool (我就是因为没看到找了半天) Step

noip2013Day2T3-华容道【一个蒟蒻的详细题解】

描述 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面,华容道是否根本就无法完成,如果能完成,最少需要多少时间. 小 B 玩的华容道与经典的华容道游戏略有不同,游戏规则是这样的: 在一个 n*m 棋盘上有 n*m 个格子,其中有且只有一个格子是空白的,其余 n*m-1个格子上每个格子上有一个棋子,每个棋子的大小都是 1*1 的: 有些棋子是固定的,有些棋子则是可以移动的: 任何与空白的格子相邻(有公共的边)的格子上的棋子都可以移动到空白