第k短路和次短路

一.求第k短路

1.什么是第k短路?第一短路就是最短路,以此类推。求某点s到某点e的第k短路就是k短路问题

2.思路:

(1)我们知道在BFS中,第一次到达终点就是到终点的最短路,那么第k次到达终点,当然就是到终点的第k短路了。但是如果直接BFS搜索下去,时间复杂度会非常高,因此我们需要剪枝,怎么剪枝呢?

(2)我们每次只需要取出每次到达终点最有希望的路径,就避开了一些没有意义的到其他点的路径。因此我们需要一个启发函数。令f = x + h(其中x为到当前点的实际距离,h为从当前点到达终点的估测最短距离),则f就估测为从起点到终点的路径长度,我们每次只要有目的有方向的前进到达终点k次即为k短路

(3)那么怎么求这个h呢?h其实为每个点到达终点的最短路,但是我们只学过某个点到其他点的最短路怎么办?当然是把终点当作起点跑最短路啊(哇笨蛋) , 但是这里有一个问题:我们需要在跑终点最短路时使用反向边,跑BFS时使用正向边(有向图),为什么呢:

 

第k短路和次短路_第1张图片(起点1,终点2)

我们如果跑终点最短路使用正向边,2是到不了1的,所以在跑BFS时,从1到2的估测函数是不存在的,但是事实是存在的。所以我们这里应该使用反向建边。而跑BFS时当然是使用正向边。

也就是说,终点反向建边能到达的点,正向边时才是能过来的点



3.求解步骤

(1)Dijkstra求终点到其他点的最短路

(2)正向边跑起点的BFS(以A*启发函数:f = x + h为排序,取出点)

4.代码:(poj2499)板子:

#include 
#include
using namespace std;
#define INF 0x3f3f3f3f
typedef long long LL;
typedef pair P;
const int maxn = 1000 + 7;
struct Edge{//正向边
    int to,next;
    LL val;
}edge[maxn*100];
struct Line{//反向边
    int to,next;
    LL val;
}line[maxn*100];
int n,m,s,e,tot,k,head[maxn],revhead[maxn];
int tot2;
bool vis[maxn];
LL dist[maxn];//保存终点到其他点的最短路
inline void addEdge(int a,int b,LL c){//正向建边
    edge[tot].to = b;edge[tot].next =  head[a];edge[tot].val = c;head[a] = tot++;
}
inline void AddEdge(int a,int b,LL c){//反向建边
   line[tot2].to = b;line[tot2].next = revhead[a];line[tot2].val = c;revhead[a] = tot2++;
}
struct Node{//BFS保存状态
   int to;
   LL cost;
   bool operator <(const Node&another)const{//排序规则按照估价函数大小由小到大
        return cost + dist[to] > another.cost + dist[another.to];//估价= 当前 + 到终点最短
   }
   Node(int a,LL c):to(a),cost(c) {}
};
inline void Dijkstra(int a){//最短路
   dist[a] = 0;
   priority_queue,greater

>que; que.push(P(0,a)); while(!que.empty()){ P p = que.top(); que.pop(); if(vis[p.second])continue; vis[p.second] = 1; LL num = p.first; for(int i = revhead[p.second];~i;i = line[i].next){//跑反向边 if(!vis[line[i].to]&&dist[line[i].to] > num + line[i].val){ dist[line[i].to] = num + line[i].val; que.push(P(dist[line[i].to],line[i].to)); } } } } inline LL BFS(int a){//BFS priority_queue que; que.push(Node(a,0)); while(!que.empty()){ Node node = que.top(); que.pop(); if(node.to==e){//到达终点次数 k--; if(k==0){ return node.cost; } } for(int i = head[node.to];~i;i = edge[i].next){//扩散(跑反向边) que.push(Node(edge[i].to,node.cost + edge[i].val)); } } return -1; } int main() { while(scanf("%d%d",&n,&m)!=EOF){ tot = tot2 = 0; memset(dist,INF,sizeof(dist)); memset(vis,0,sizeof(vis)); memset(head,-1,sizeof(head)); memset(revhead,-1,sizeof(revhead)); for(int i = 0;i

 

 

二.求次短路

1.dist[ i ][ 0 ]表示到点 i 的最短路 , dist[ i ][ 1 ]表示到点 i 的次短路

2.

最短路何时更新:当dist[ i ][ 0 ] > len(j) + val( j , i )时,直接更新最短路

何时更新次短路:   dist[ i ][ 0 ]  < len(j) + val( j , i )  < dist[ i ][ 1 ]时,更新次短路

3.代码:

#include 
#include
using namespace std;
#define INF 0x3f3f3f3f
typedef pairP;
const int maxn = 100000 + 7;
struct Edge{
   int to,next,val;
}edge[maxn];
int n,m,head[maxn],dist[maxn][2],tot;
void addEdge(int a,int b,int c){
   edge[tot].to = b;edge[tot].val = c;edge[tot].next = head[a];head[a] = tot++;
}
void Dijkstra(int s){
    for(int i = 0;i<=n;i++)dist[i][0] = dist[i][1] = INF;
    dist[s][0] = 0;
    priority_queue, greater

>que; que.push(P(0,s)); while(!que.empty()){ P p = que.top(); que.pop(); if(p.first > dist[p.second][1])continue; for(int i = head[p.second];~i;i = edge[i].next){ int d = p.first + edge[i].val; if(dist[edge[i].to][0] > d){//更新最短路 swap(dist[edge[i].to][0] , d);//交换!!! que.push(P(dist[edge[i].to][0],edge[i].to));//注意d值已经被交换了 } if(dist[edge[i].to][1] > d&&dist[edge[i].to][0] < d){//更新次短路 dist[edge[i].to][1] = d; que.push(P(d,edge[i].to)); } } } } int main() { tot = 0; memset(head,-1,sizeof(head)); scanf("%d%d",&n,&m); for(int i = 0;i

 

你可能感兴趣的:(-----图论-----)