AcWing 383. 觀光 ( dijkstra拆點求最短路數)

整理的算法模板:ACM算法模板總結(分類詳細版)

 

“您的個人假期”旅行社組織了一次比荷盧經濟聯盟的巴士之旅。

比荷盧經濟聯盟有很多公交線路。

每天公共汽車都會從一座城市開往另一座城市。

沿途汽車可能會在一些城市(零或更多)停靠。

旅行社計劃旅途從 S 城市出發,到 F 城市結束。

由於不同旅客的景點偏好不同,所以爲了迎合更多旅客,旅行社將爲客戶提供多種不同線路。

遊客可以選擇的行進路線有所限制,要麼滿足所選路線總路程爲 S 到 F 的最小路程,要麼滿足所選路線總路程僅比最小路程多一個單位長度。

3463_1.png

如上圖所示,如果S = 1,F = 5,則這裏有兩條最短路線1->2->5,1->3->5,長度爲6;有一條比最短路程多一個單位長度的路線1->3->4->5,長度爲7。

現在給定比荷盧經濟聯盟的公交路線圖以及兩個城市 S 和 F,請你求出旅行社最多可以爲旅客提供多少種不同的滿足限制條件的線路。

輸入格式

第一行包含整數 T,表示共有 T 組測試數據。

每組數據第一行包含兩個整數 N 和 M,分別表示總城市數量和道路數量。

接下來 M 行,每行包含三個整數 A,B,L,表示有一條線路從城市 A 通往城市 B,長度爲 L。

需注意,線路是 單向的,存在從A到B的線路不代表一定存在從B到A的線路,另外從城市A到城市B可能存在多個不同的線路。

接下來一行,包含兩個整數 S 和 F,數據保證 S 和 F 不同,並且S、F之間至少存在一條線路。

輸出格式

每組數據輸出一個結果,每個結果佔一行。

數據保證結果不超過109109。

數據範圍

2≤N≤10002≤N≤1000,
1≤M≤100001≤M≤10000,
1≤L≤10001≤L≤1000,
1≤A,B,S,F≤N1≤A,B,S,F≤N

輸入樣例:

2
5 8
1 2 3
1 3 2
1 4 5
2 3 1
2 5 3
3 4 2
3 5 4
4 5 3
1 5
5 6
2 3 1
3 2 1
3 1 10
4 5 2
5 2 7
5 2 7
4 1

輸出樣例:

3
2
難度:中等
時/空限制:1s / 64MB
總通過數:374
總嘗試數:843
來源:《算法競賽進階指南》
算法標籤 :最短路

首先最短路計數問題最好用dijkstra算法(權值0,1的圖可以直接bfs進行寬搜);因爲dijkstra具有天生的拓撲序;假設算當前點u的時候要用到前面用過的點v,那麼不可能下次用u來更新v;也就說沒有0環的存在;spfa算法不具有拓撲序,但可以轉換爲最短路樹問題計算;

這道題可以對每個點進行拆點;以前一個點有兩個信息:最短距離  點的id;拆點之後多了一個信息:type;這個type代表的這個點的類型;那麼這兩個點分別是  最短距離點  和  次短距離點;然後按照dijkstra+heap跑一遍就可;

注意,一定要先更新次短路點的信息,因爲最短路沒有更新的時候,次最短路可能更新;而次最短路更新的時候,最短路一定會更新;

#include <bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<pair<int,int>,int> PII;

int n, m, S, F;
const int N=1010,M=20010;
int h[N], e[M], w[M], ne[M], idx;
int dis[N][2], cnt[N][2];
bool st[N][2];
void add(int a, int b, int c)
{
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
}
int dijkstra(int root)
{
    memset(dis,0x3f,sizeof dis);
    memset(st,false,sizeof st);
    memset(cnt,0,sizeof cnt);
    dis[root][0]=0,cnt[root][0]=1;
    priority_queue<PII,vector<PII>,greater<PII> > heap;
    heap.push({{0,0},root});
    while(!heap.empty())
    {
        auto t=heap.top();
        heap.pop();
        int ver=t.y,type=t.x.y,distance=t.x.x,res=cnt[ver][type];
        if(st[ver][type]) continue;
        st[ver][type] = true;
        for(int i=h[ver];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(dis[j][0]>distance+w[i])
            {
                dis[j][1]=dis[j][0],cnt[j][1]=cnt[j][0];
                heap.push({{dis[j][1],1},j});
                dis[j][0]=distance+w[i],cnt[j][0]=res;
                heap.push({{dis[j][0],0},j});
            }
            else if(dis[j][0]==distance + w[i]) cnt[j][0]+=res;
            else if(dis[j][1]>distance+w[i])
            {
                dis[j][1]=distance+w[i];
                cnt[j][1]=res;
                heap.push({{dis[j][1],1},j});
            }
            else if(dis[j][1]==distance + w[i])
            {
                cnt[j][1]+=res;
            }
            
        }
    }
    int ans = cnt[F][0];
    if (dis[F][0] + 1 == dis[F][1]) ans += cnt[F][1];

    return ans;
}
int main()
{
    int t;
    cin >>t;
    while(t--)
    {
        idx=0;
        memset(h,-1,sizeof h);
        int n,m;
        cin >>n>>m;
        for(int i=0;i<m;i++)
        {
            int a,b,c;
            cin >>a>>b>>c;
            add(a,b,c);
        }
        cin >>S>>F;
        
        cout <<dijkstra(S)<<endl;
    }
    
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章