您的位置:首页 > 其它

poj--2449 Remmarguts' Date(k短路)

2016-09-16 20:32 399 查看
Remmarguts’ Date

题解

求s到t的第k短路的长度。

SPFA + A*算法。

A*算法通过一个估价函数f(h)来估计图中的当前点p到终点的距离,并由此决定它的搜索方向,当这条路径失败时,它会尝试其他路径。

估价函数 = 当前值+当前位置到终点的距离,即f(p)=g(p)+d(p)

其中,g(p)为当前从s到p所走的路径长度,d(p)为从点p到终点t的最短路长度,f(p)则为从s到p再到t的路径长度。

也就是说,每次的扩展是有方向的,它会选择估价函数值最小的一条路径走。

d(p)可以在A*搜索之前进行预处理,只要将原图的所有边反向,再从终点t做一次单源最短路径就能得到每个点的d(p)值。

具体步骤:

将有向图的所有边反向,以t为源点,计算t到其他点的最短路d[].

建一个优先队列,将s加入到队列中;

从优先队列中弹出f(p)最小的点p,如果p就是t,计算t出队的次数,如果已经是t的第k次出队,那么当前路径的长度就是s到t的第k短路的长度;否则遍历与p相连的所有边,将扩展出的到p的邻接点信息加入到优先队列。

注意当 s == t 的时候,需要计算 k + 1 短路,因为s到t这条距离为0的路径不能算在这k短路中。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <queue>
#include <cstring>
using namespace std;

const int maxn = 1000 + 3;
const int inf  = 0x3f3f3f3f;

struct Edge{
int to, w;
Edge(int to, int w):to(to), w(w){}
};
vector<Edge> G1[maxn], G2[maxn];
int  n, m, s, t, k;
int  d[maxn];
bool vis[maxn];

void SPFA(){
memset(vis, 0, sizeof(vis));
for(int i = 1; i <= n; ++i) d[i] = inf;
queue<int> Q;
Q.push(t);
d[t] = 0, vis[t] = true;

while(!Q.empty()){
int u = Q.front();Q.pop();
vis[u] = false;

for(int i = 0; i < G2[u].size(); ++i){
int v = G2[u][i].to, w = G2[u][i].w;
if(d[v] > d[u] + w){
d[v] = d[u] + w;
if(!vis[v]){
vis[v] = true;
Q.push(v);
}
}
}
}
}

struct Node{
int to;
int g, f; // f = g + d
Node(int to, int g, int f):to(to), g(g), f(f){}
bool operator < (const Node& rhs) const{
return rhs.f == f ? rhs.g < g : rhs.f < f;
}
};

int Astar(int s, int t){
priority_queue<Node> PQ;
if(s == t) k++;
if(d[s] == inf) return -1;
PQ.push(Node{s, 0, d[s]});  // to, g, f
while(!PQ.empty()){
Node x = PQ.top(); PQ.pop();
if(x.to == t){
if(--k == 0) return x.g;
}
for(int i = 0; i < G1[x.to].size(); ++i){
int v = G1[x.to][i].to, w = G1[x.to][i].w;
PQ.push(Node(v, x.g + w, x.g + w + d[v]));
}
}
return -1;
}

int main(){
#ifdef EXMY
freopen("data.in", "r", stdin);
#endif // EXMY
/// 15264K  329MS
while(~scanf("%d %d", &n, &m)){
for(int i = 0; i <= n; ++i){
G1[i].clear();
G2[i].clear();
}
int u, v, w;
for(int i = 0; i < m; ++i){
scanf("%d %d %d", &u, &v, &w);
G1[u].push_back(Edge(v, w));
G2[v].push_back(Edge(u, w));    // 反向图
}
scanf("%d %d %d", &s, &t, &k);
SPFA();
//for(int i = 1; i <= n; ++i) cout << d[i] << " ";
printf("%d\n", Astar(s, t));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  poj k短路 图论 SPFA Astar