k短路算法

k短路算法

求解k短路用到了A* 算法,A* ( A star )算法,又称启发式搜索算法,与之相对的,dfs与bfs都成为盲目型搜索;即为带有估价函数的优先队列BFS称为A*算法。

该算法的核心思想为设计一个估价函数,估价函数需要满足下面几个准则:

1:设当前状态state到目标状态所需的估计值为\(f(state)\)。

2:在未来的搜索中,实际求出的从当前状态state到目标状态的最小代价为\(g(state)\)。

3:对于任意的\(state\),应该有\(f(state)<=g(state)\)。

之后每次取出“当前代价+未来估价最小的状态,最终更新到目标状态上,就能得到最优解。

A*算法的应用非常广,被广泛应用于最优路径求解和一些策略设计问题中。

首先跑一下Dijkstra或者SPFA反向求一下终点到各个点的最短路,然后A*求出k短路,上代码:

#include<cstdio>
#include<cstring>
#include<queue>

using namespace std;
const int maxn=1e5+10;
const int inf=0x3f3f3f3f;
int head[maxn],head1[maxn],tot,tot1;
int n,m,s,t,k,dis[maxn];
struct Edge{
    int nex,to,val;
}edge[maxn],edge1[maxn];
struct  node{
    int to,f,g;                 //估价函数和实际代价
    friend bool operator <(const node& a,const node& b){
        if(a.f==b.f)    return a.g>b.g;
        return a.f>b.f;
    }
}now,temp;
bool vis[maxn];
void add(int from,int to,int val)
{
    edge[++tot].to=to;
    edge[tot].val=val;
    edge[tot].nex=head[from];
    head[from]=tot;
}
void add1(int from,int to,int val)
{
    edge1[++tot1].to=to;
    edge1[tot1].val=val;
    edge1[tot1].nex=head1[from];
    head1[from]=tot1;
}
queue<int> q;
bool spfa(int s)
{
    for(int i=1;i<=n;++i){
        dis[i]=inf;
        vis[i]=false;
    }
    vis[s]=1;
    dis[s]=0;
    while(!q.empty())   q.pop();
    q.push(s);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        vis[u] = 0;
        for(int i=head1[u];i!=-1;i=edge1[i].nex){
            int v=edge1[i].to;
            if(dis[v]>dis[u]+edge[i].val){
                dis[v]=dis[u]+edge[i].val;
                if(vis[v])  continue;
                vis[v] = 1;
                q.push(v);
            }
        }
    }
    return true;
}
priority_queue<node> que;
int A_star()
{
    int cnt=0;
    while(!que.empty()) que.pop();
    if(!spfa(t)||dis[s]==inf)   return -1;
    if(s==t)    ++k;            //起点跟终点相同,不能算dis=0这一条
    now.to=s;
    now.g=0;
    now.f=now.g+dis[now.to];
    que.push(now);
    while(!que.empty()){
        now = que.top();
        que.pop();
        if(now.to==t)   cnt++;
        if(cnt==k)  return now.g;
        for(int i=head[now.to];i!=-1;i=edge[i].nex){
            temp.to=edge[i].to;
            temp.g=now.g+edge[i].val;
            temp.f=temp.g+dis[temp.to];
            que.push(temp);
        }
    }
    return -1;
}

int main()
{
    while(scanf("%d %d",&n,&m)==2)
    {
        for(int i=1;i<=n;++i){
            head[i]=head1[i]=-1;
        }
        tot=tot1=0;
        for(int i=1;i<=m;++i){
            int a,b,val;
            scanf("%d %d %d",&a,&b,&val);
            add(a,b,val);
            add1(b,a,val);
        }
        scanf("%d %d %d",&s,&t,&k);
        printf("%d\n",A_star());
    }
}

原文地址:https://www.cnblogs.com/StungYep/p/12252248.html

时间: 2024-10-22 19:56:20

k短路算法的相关文章

浅谈k短路算法

An Old but Classic Problem 给定一个$n$个点,$m$条边的带正权有向图.给定$s$和$t$,询问$s$到$t$的所有权和为正路径中,第$k$短的长度. Notice 定义两条路径不同,当且仅当它们的边集中存在一条边,使得它只在其中的一条路径上. Solution#1 Shortest Path & A* 对于Dijstra算法,有一个结论就是,当一个点第$k$次出队的时候,此时路径长度就是$s$到它的第$k$短路. 那为什么还要A*呢?我试了试,写了个Dijstra,

POJ 2449 Remmarguts&#39; Date ( 第 k 短路 &amp;&amp; A*算法 )

题意 : 给出一个有向图.求起点 s 到终点 t 的第 k 短路.不存在则输出 -1 #include<stdio.h> #include<string.h> #include<queue> #include<algorithm> using namespace std; const int INF = 0x3f3f3f3f; const int maxn = 1024; const int maxm = 100008; struct EDGE{ int v

A*算法的认识与求第K短路模板

现在来了解A*算法是什么 现在来解决A*求K短路问题 在一个有权图中,从起点到终点最短的路径成为最短路,第2短的路成为次短路,第3短的路成为第3短路,依此类推,第k短的路成为第k短路.那么,第k短路怎么求呢? 对于第k短路,可以想到的一个比较朴素的算法就是广度优先搜索,使用优先队列从源点s进行广搜,当第k次搜索到终点t时,所的长度即所求但是这种方法在运行过程中会产生特别多的状态,当图比较简单.k比较小时,可以一试,但是当k较大或者图中点数较多时,会面临爆栈的危险.目前使用比较多的算法是单源最短路

次短路 + 第K短路 模版

虽然从字面上看,次短路和第2短路是一样的.但是我在题目中遇到的却不是这样的. 在有些题目中,需要判断次短路是否存在.比如说,u.v之间只有一条路径.那么只有最短路.次短路是不存在的.这时候,解题方法是先求出最短路,然后枚举删除最短路径中的边,然后求最小值.题目可以看poj3986. 第K短路的实现是 SPFA + A* 算法. A*算法通过一个估价函数f(h)来估计途中的当前点p到终点的距离,并由此决定它的搜索方向,当这条路径失败时,它会尝试其他路径.对于A*,估价函数 = 当前值 + 当前位置

POJ 2449Remmarguts&#39; Date 第K短路

Remmarguts' Date Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 29625   Accepted: 8034 Description "Good man never makes girls wait or breaks an appointment!" said the mandarin duck father. Softly touching his little ducks' head, h

POJ--2449--Remmarguts&amp;#39; Date【dijkstra_heap+A*】第K短路

链接:http://poj.org/problem?id=2449 题意:告诉你有n个顶点,m条边.并把这些边的信息告诉你:起点.终点.权值.再告诉你s.t.k.需求出s到t的第k短路,没有则输出-1. 第K短路裸题,A*算法没接触过.參考了这篇博客:http://www.cnblogs.com/n-u-l-l/archive/2012/07/29/2614194.html 下面大体字摘自这篇博文,讲的非常清楚: 对于第k短路,能够想到的一个比較朴素的算法就是广度优先搜索,使用优先队列从源点s进

图论(A*算法,K短路) :POJ 2449 Remmarguts&#39; Date

Remmarguts' Date Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 25216   Accepted: 6882 Description "Good man never makes girls wait or breaks an appointment!" said the mandarin duck father. Softly touching his little ducks' head, h

【k短路&amp;A*算法】BZOJ1975: [Sdoi2010]魔法猪学院

Description 找出1~k短路的长度. Solution k短路的求解要用到A*算法 A*算法的启发式函数f(n)=g(n)+h(n) g(n)是状态空间中搜索到n所花的实际代价 h(n)是n到结束状态最佳路径的估计代价 关于h(n)的选取,当h(n)<实际代价时,搜索慢但可出解:h(n)=实际代价时,正确率与效率最高:h(n)>实际代价,快但只能得到近似解. 但在k短路问题中,h(n)是可以选到准确值的,就是n到结束节点的最短路,预处理时从结束节点做一次单源最短路即可. 按广搜的方式

poj 2449 Remmarguts&#39; Date(K短路,A*算法)

http://poj.org/problem?id=2449 大致题意:给出一个有向图,求从起点到终点的第K短路. K短路与A*算法详解  学长的博客... 算法过程 #include <stdio.h> #include <iostream> #include <algorithm> #include <set> #include <map> #include <vector> #include <math.h> #in