1. 程式人生 > >POJ-3255 Roadblocks(次短路)

POJ-3255 Roadblocks(次短路)

Bessie has moved to a small farm and sometimes enjoys returning to visit one of her best friends. She does not want to get to her old home too quickly, because she likes the scenery along the way. She has decided to take the second-shortest rather than the shortest path. She knows there must be some second-shortest path.

The countryside consists of R (1 ≤ R ≤ 100,000) bidirectional roads, each linking two of the N (1 ≤ N ≤ 5000) intersections, conveniently numbered 1…N. Bessie starts at intersection 1, and her friend (the destination) is at intersection N.

The second-shortest path may share roads with any of the shortest paths, and it may backtrack i.e., use the same road or intersection more than once. The second-shortest path is the shortest path whose length is longer than the shortest path(s) (i.e., if two or more shortest paths exist, the second-shortest path is the one whose length is longer than those but no longer than any other path).

Input
Line 1: Two space-separated integers: N and R
Lines 2… R+1: Each line contains three space-separated integers: A, B, and D that describe a road that connects intersections A and B and has length D (1 ≤ D ≤ 5000)
Output
Line 1: The length of the second shortest path between node 1 and node N
Sample Input
4 4
1 2 100
2 4 200
2 3 250
3 4 100
Sample Output
450
Hint
Two routes: 1 -> 2 -> 4 (length 100+200=300) and 1 -> 2 -> 3 -> 4 (length 100+250+100=450)

**題意:**求次短路
題解 和最短路一樣做,在dijkstra中多加個dist2求次短路,保證符合限制條件更新,必須大於最短路且小於上次被記錄的次短路

#include<stdio.h>///次短路
#include<queue>///大體和最短路差不多,其實就是用最短路而計算出的次短路
#include<string.h>
#include<algorithm>
#include<vector>
using namespace std;
int dist[5008],dist2[5008];///最短路和次短路分別用陣列存
struct edge
{
    int to,val;
    edge(int a=0,int b=0):to(a),val(b) {}///結構體建構函式
    bool operator <(const edge &a)const///結構體過載運算子
    {
        if(val==a.val)return to>a.to;
        return val>a.val;///此處雖然是大於號,但是在優先佇列中是從小到大排列,隊首為最小值
    }
};
vector<edge>v[5008];
void dijkstra(int s)
{
    memset(dist,0x3f,sizeof(dist));
    memset(dist2,0x3f,sizeof(dist2));
    priority_queue<edge>q;
    q.push(edge(s,0));///注意起點從1開始而不是從0
    while(!q.empty())
    {
        edge top=q.top();///取出最小值
        q.pop();
        for(int i=0; i<v[top.to].size(); i++)
        {
            edge tmp=v[top.to][i];///和最短路一樣,先更新最短路,遍歷取出節點所能到達的所有節點,更新所有能到達節點的最短路,這裡的新權值,暫時用一個dis做臨時儲存
            int dis=tmp.val+top.val;
            if(dist[tmp.to]>dis)///若新權值比記錄的最短路陣列要小
            {
                swap(dist[tmp.to],dis);///更新最短路!且,臨時儲存這個被更換的"前最短路",用來之後更新次短路,因為這個最短路是僅次於新權值的最短路。
                q.push(edge(tmp.to,dist[tmp.to]));///將新最短路塞入佇列
            }
            if(dist2[tmp.to]>dis&&dis>dist[tmp.to])///無論這個dis是否被之前的最短路通過更換來更新過,它都是一個在最短路基礎上加上新權值而得到的權值,只要符合小於原次短路且大於最短路的條件
            {///都能用來更新次短路
                dist2[tmp.to]=dis;
                q.push(edge(tmp.to,dist2[tmp.to]));///將次短路放回佇列中繼續更新(用於更新次短路)
            }
        }
    }
}
int main()
{
    int n,r,to,val,from;
    while(scanf("%d%d",&n,&r)!=EOF)
    {
        for(int i=0; i<=5000; i++)v[i].clear();
        for(int i=0; i<r; i++)
        {
            scanf("%d%d%d",&from,&to,&val);
            v[from].push_back(edge(to,val));///無向圖
            v[to].push_back(edge(from,val));
        }
        dijkstra(1);
        printf("%d\n",dist2[n]);
    }
}
/*
有一個關係是 dist2【i】> dx >dist[i] 那麼這個dx是可以更新dist2的,
然後將這個dx更新之後又放入優先佇列中,用來做下一次可能出現的次短
路的更新,這樣,也許沒有進到第一個if裡去更新最短路,但是仍然有可
能用於構造下一個次短路,所以第二個push應該是用來更新不是最短路的次短路
*/