所谓K短路,就是从s到t的第K短的路,第1短就是最短路。

如何求第K短呢?有一种简单的方法是广度优先搜索,记录t出队列的次数,当t第k次出队列时,就是第k短路了。但点数过大时,入队列的节点过多,时间和空间复杂度都较高。

A*是在搜索中常用的优化,一种启发式搜索。简单的说,它可以用公式表示为f(n) = g(n) + f(n),其中,f(n)是从s经由节点n到t的估价函数,g(n)是在状态空间中从s到n的实际代价,h(n)是从n到t的最佳路径估计代价。在设计中,要保证h(n)<= n到t的实际代价,这一点很重要,h(n)越接近真实值,速度越快。

由于启发函数的作用,使得计算机在进行状态转移时尽量避开不可能产生最优解的分支,而选择相对较接近最优解的路径进行搜索,降低了时间和空间复杂度。

算法过程:

1. 将图反向,用dijstra+heap求出t到所有点的最短距离,目的是求所有点到点t的最短路,用dis[i]表示i到t的最短路,其实这就是A*的启发函数,显然:h(n)<= n到t的实际代价。

2. 定义估价函数。我们定义g(n)为从s到n所花费的代价,h(n)为dis[n],显然这符合A*算法的要求。

3. 初始化状态。状态中存放当前到达的点i,fi,gi。显然,fi=gi+dis[i]。初始状态为(S,dis[S],0),存入优先级队列中。

4. 状态转移。假设当前状态所在的点v相邻的点u,我们可以得到转换:(V,fv,gv)-->(U,fu+w[v][u],gv+w[v][u])。

5. 终止条件。每个节点最多入队列K次,当t出队列K次时,即找到解。

例:POJ2449

题意:裸的K短路。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAX = 1005;
int n,m;
int start,end,k;
struct Edge
{
    int w;
    int to;
    int next;
};
Edge e[100005];
int head[MAX],edgeNum;
int dis[MAX];   //dis[i]表示从i点到end的最短距离
bool vis[MAX];
int cnt[MAX];
vector<Edge> opp_Graph[MAX];
 
struct Node
{
    int f,g;    //f = g+dis[v]
    int v;      //当前到达的节点
    Node(int a, int b,int c):f(a),g(b),v(c){}
    bool operator < (const Node& a) const
    {
        return a.f < f;
    }
};
 
void addEdge(int from, int to, int w)
{
    e[edgeNum].to = to;
    e[edgeNum].w = w;
    e[edgeNum].next = head[from];
    head[from] = edgeNum++;
}
 
void dijikastra(int start)
{
    int i;
    memset(vis,0,sizeof(vis));
    for(i = 1; i <= n; i++)
        dis[i] = INF;
    dis[start] = 0;
    priority_queue<Node> que;
    que.push(Node(0,0,start));
    Node next(0,0,0);
    while(!que.empty())
    {
        Node now = que.top();
        que.pop();
        if(vis[now.v])              //从集合T中选取具有最短距离的节点
            continue;
        vis[now.v] = true;          //标记节点已从集合T加入到集合S中
        for(i = 0; i < opp_Graph[now.v].size(); i++)    //更新从源点到其它节点(集合T中)的最短距离
        {
            Edge edge = opp_Graph[now.v][i];
            if(!vis[edge.to] && dis[now.v] + edge.w < dis[edge.to])     //加不加前面的判断无所谓
            {
                dis[edge.to] = dis[now.v] + edge.w;
                next.f = dis[edge.to];
                next.v = edge.to;
                que.push(next);
            }
        }
    }
}
 
int A_Star()
{
    int i;
    priority_queue<Node> que;
    if(dis[start] == INF)
        return -1;
    que.push(Node(dis[start],0,start));
    Node next(0,0,0);
    while(!que.empty())
    {
        Node now = que.top();
        que.pop();
        cnt[now.v]++;
        if(cnt[end] == k) return now.f;
//严格最短路的判断条件为 cnt[end] == k&&now.f>min(zuiduanlu)
        if(cnt[now.v] > k)
            continue;
        for(i = head[now.v]; i != -1; i = e[i].next)
        {
            next.v = e[i].to;
            next.g = now.g + e[i].w;
            next.f = next.g + dis[e[i].to];
            que.push(next);
        }
    }
    return -1;
}
 
int main()
{
    int i;
    int from,to,w;
    edgeNum = 0;
    memset(head,-1,sizeof(head));
    memset(opp_Graph,0,sizeof(opp_Graph));
    memset(cnt,0,sizeof(cnt));
    scanf("%d %d",&n,&m);
    Edge edge;
    for(i = 1; i <= m; i++)
    {
        scanf("%d %d %d",&from,&to,&w);
        addEdge(from,to,w);
        edge.to = from;
        edge.w = w;
        opp_Graph[to].push_back(edge);
    }
    scanf("%d %d %d",&start,&end,&k);
    if(start == end)
        k++;
    dijikastra(end);
    int result = A_Star();
    printf("%d\n",result);
    return 0;
}
 

第K短路+严格第K短路的更多相关文章

  1. HDU 4396More lumber is required 过至少K条边的最短路

    /* ** 题目要求过最少k条边的最短路 */ #include <iostream> #include <cstdio> #include <cstring> # ...

  2. BZOJ2125 最短路 【仙人掌最短路】

    题目 给一个N个点M条边的连通无向图,满足每条边最多属于一个环,有Q组询问,每次询问两点之间的最短路径. 输入格式 输入的第一行包含三个整数,分别表示N和M和Q 下接M行,每行三个整数v,u,w表示一 ...

  3. [CareerCup] 13.1 Print Last K Lines 打印最后K行

    13.1 Write a method to print the last K lines of an input file using C++. 这道题让我们用C++来打印一个输入文本的最后K行,最 ...

  4. 一些简单的问题. 2的10次方与k (涉及到b k m的要用乘来解读)

    2的10次方是k k就表示2的10次方 2的16次方,解读为 2的6次方(64)*2的10次方(k)  简写为64k    64k=64*k 同理2的20次方  解读为2的10次方*2的10次方  k ...

  5. 机器学习 —— 基础整理(三)生成式模型的非参数方法: Parzen窗估计、k近邻估计;k近邻分类器

    本文简述了以下内容: (一)生成式模型的非参数方法 (二)Parzen窗估计 (三)k近邻估计 (四)k近邻分类器(k-nearest neighbor,kNN) (一)非参数方法(Non-param ...

  6. 快速排序/快速查找(第k个, 前k个问题)

    //快速排序:Partition分割函数,三数中值分割 bool g_bInvalidInput = false; int median3(int* data, int start, int end) ...

  7. 在数组a中,a[i]+a[j]=a[k],求a[k]的最大值,a[k]max——猎八哥fly

    在数组a中,a[i]+a[j]=a[k],求a[k]的最大值,a[k]max. 思路:将a中的数组两两相加,组成一个新的数组.并将新的数组和a数组进行sort排序.然后将a数组从大到小与新数组比较,如 ...

  8. [LeetCode] Top K Frequent Words 前K个高频词

    Given a non-empty list of words, return the k most frequent elements. Your answer should be sorted b ...

  9. [LeetCode] K Inverse Pairs Array K个翻转对数组

    Given two integers n and k, find how many different arrays consist of numbers from 1 to n such that ...

随机推荐

  1. Struts2-学习笔记系列(10)-自定义类型转换

    注意name=user和对应action中的实例名称一致 这些代码是写在HTML文件中的 <s:form action="login"> <s:textfield ...

  2. 搭建WEB、NFS共享、sersync实时同步以及全网定时备份服务流程

    本次实验的主要目的: 1.搭建web服务,使用nfs服务共享的/data目录挂载到web站点目录上. 2.nfs服务器与backup服务器使用sersync实时同步/data目录中的文件. 3.bac ...

  3. 009-数组-C语言笔记

    009-数组-C语言笔记 学习目标 1.[掌握]数组的声明 2.[掌握]数组元素的赋值和调用 3.[掌握]数组的初始化 4.[掌握]数组的遍历 5.[掌握]数组在内存中的存储 6.[掌握]数组长度计算 ...

  4. AJ学IOS(54)多线程网络之NSOperation重要知识

    AJ分享,必须精品 一:队列的类型与队列添加任务 1: 主队列 [NSOperationQueue mainQueue] 添加到”主队列”中的操作,都会放到主线程中执行. 2:非主队列 [[NSOpe ...

  5. vuepress+gitee 构建在线项目文档

    目录 快速入门 在现有vue项目中安装本地开发依赖vuepress 在现有vue项目根目录下创建docs目录 创建并配置文档首页内容 运行,查看效果 可能会出现vue和vue-server-rende ...

  6. 学习Salesforce | Platform Developer Ⅰ 平台初级开发认证考试指南及备考资源

    一.平台开发人员考试计划 Salesforce平台开发人员初级认证面向具有在Lightning平台上构建自定义应用程序的知识.技能和经验的个人. 该认证考核Lightning平台的基本编程能力,并会使 ...

  7. 【原创干货】大数据Hadoop/Spark开发环境搭建

    已经自学了好几个月的大数据了,第一个月里自己通过看书.看视频.网上查资料也把hadoop(1.x.2.x).spark单机.伪分布式.集群都部署了一遍,但经历短暂的兴奋后,还是觉得不得门而入. 只有深 ...

  8. CSRF(跨站请求伪造)学习总结

    前言 参考大佬的文章,附上地址 https://www.freebuf.com/articles/web/118352.html 什么是CSRF? CSRF,中文名字,跨站请求伪造,听起来是不是和XS ...

  9. 6.表单提交,input键盘变搜索,有关自定义属性input操作

    1.键盘变搜索 1.) 在form 上加action="#", 2.)input type=search, 3.)此时会提交到 #,需要再添加一个input display=non ...

  10. 【python】显示图片 并随意缩放图片大小 图片归一化

    cv2.namedWindow("image_",0)  cv2.imshow("image_",image)就可以随意缩放显示图片的窗口大小啦. ------ ...