http://poj.org/problem?id=3255
1番目の頂点からN番目の頂点への経路の内二番目に短いものの長さを求めよ。
(最短経路が二つ以上ある場合、その値を出力)
アリ本p102より。ダイクストラ法の改良。
最小の距離と二番目に小さい距離をdist,dist2に記憶するようダイクストラ法を進めればOKです。
ただし、既に通った/通っていないかでヒープに追加するかの判断はできません。
また、1->2->1->2のような経路がdist2となる場合もあるので注意が必要です。
アリ本ではdist2を更新するブロックで
if(dist2[e.to] > d2 && dist[e.to] < d2)
となっていますが、dist[e.to] < d2 は不要です
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <functional>
#include <algorithm>
#define INF (1 << 30)
#define MAX_N 5001
#define MAX_R 100001
#define DBG 0
using namespace std;
int N,R;
struct edge{int to, cost;};
typedef pair<int, int> P;
vector<edge> G[MAX_N];
int dist[MAX_N];
int dist2[MAX_N];
void solve(){
priority_queue<P, vector<P>, greater<P> > pq;
fill(dist, dist+N, INF);
fill(dist2, dist2+N, INF);
dist[0] = 0;
pq.push(P(0, 0));
while(!pq.empty()){
P p = pq.top();
if(DBG){
cout << p.first << " " << p.second << endl;
}
pq.pop();
int v = p.second, d = p.first;
if(dist2[v] < d){
continue;
}
for(int i = 0; i < G[v].size(); i++){
edge &e = G[v][i];
int d2 = d + e.cost;
if(dist[e.to] > d2){
swap(dist[e.to], d2);
pq.push(P(dist[e.to], e.to));
}
if(dist2[e.to] > d2){
dist2[e.to] = d2;
pq.push(P(dist2[e.to], e.to));
}
}
}
cout << dist2[N-1] << endl;
}
int main(){
cin >> N >> R;
for(int i = 0; i < R; i++){
int s,t,c;
scanf("%d %d %d", &s, &t, &c);
G[s-1].push_back((edge){t-1, c});
G[t-1].push_back((edge){s-1, c});
}
solve();
return 0;
}
こっちの方が個人的にはわかりやすい。
if(dist2[e.to] > d2){
dist2[e.to] = d2;
if(dist[e.to] > dist2[e.to]){
swap(dist[e.to], dist2[e.to]);
pq.push(P(dist[e.to], e.to));
}
else{
pq.push(P(dist2[e.to], e.to));
}
}
0 件のコメント:
コメントを投稿