【圖論】Dijkstra算法經典題目 之航線

航線–Dijkstra算法經典題目

圖論除了最小生成樹,Kruskal以外,Dijkstra算法也是重點的模塊,Dijkstra算法變種題很多,經典的我也是收藏一下,以後方便尋找,hah

題目描述(廢話,建議不看)

“呼!!終於到了,可是接下來要怎麼走才能到達楚楚街港港呢?”亮亮在醋溜港直髮愁。 突然“啾”的一下,一隻銀色小船出現在亮亮的面前,
上面坐着小精靈丹丹“又見面了,有什麼可以幫助你的麼?”小精靈向亮亮眨了眨眼睛,微笑着說。 “我想去楚楚街港,但我不知道要怎麼走,
請問你可以告訴我麼?”亮亮按捺着激動的	心	情輕聲問道。 “楚楚街港呀......那是個特別美好的地方”小精靈歪着頭想了想,說“我只能告訴
你大海上所有的航線,		  剩下的就只能靠你自己啦~” “只有所有的航
線呀”,亮亮的內心再三掙扎,卻又沒有其他的辦法。 “不管有多困難,我一定要達到楚楚街港,請你告訴我吧”亮亮堅定地對小精靈說。
 小精靈欣賞地點了點頭,遞給亮亮一張航線圖,並叮囑道“時限是1000天,一定要到哦~”,然後如來時一般“啾”的一聲,消失了。 亮亮現在
 迫切地想要抵達楚楚街  港,請問亮亮最快能在第幾天抵達楚楚街港呢?

輸入描述:

一行包含兩個整數N(2<=N<=500),M(1<=M<=2000),用單個空格隔開。表示公有N個港,M條航線。起點爲1,終點爲N。
接下來M行,每行包含五個整數P,Q(1<=P,Q<=n), K(1<=K<=1000), X,Y(0<=X,Y<=10000),代表P,Q兩個港有航線並需要K天,
並且該航線在第X天到第Y天天氣惡劣	不可通行。

輸出描述:

一個整數,即亮亮最快能在第幾天抵達楚楚街港

輸入

4 4      
2 1 1 7 13
4 3 2 10 11
1 3 8 9 12
2 3 3 2 10

輸出

14

算法思想:

  1. 在這裏用臨界矩陣作爲鄰接表存儲每一個節點的信息,由於信息很多,所以不考慮用pair<>而考慮用臨界節點Node來存儲所有的節點信息
  2. 若行船時間要與風暴時間有重合需要等到暴風雨結束才能出發

如果還不是很理解dijkstra算法的同學建議先點擊:dijkstra算法模板詳細介紹

這裏的taken數組其實就是一個標記是否訪問過,是否能作爲下一次更新最短路徑的bool型的st[]數組

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <climits>
#include <vector>
using namespace std;
const int maxn = 500 + 5;
int dp[maxn], taken[maxn], n, m;
 
struct Node{
    int x, y, val, start, end;
    Node(int a, int b, int c, int d, int e){
        x = a; y = b; val = c; start = d; end = e;
    }
};
vector<Node> v[maxn]; //每一個起始點 對應的結構體, 作爲拓撲圖,這裏是結構體Node作爲拓撲圖
 
int main(){
    while(scanf("%d%d", &n, &m) != EOF){
        memset(dp, 0x3f, sizeof(dp));  //初始化dp數組爲0x3f,dp數組就是距離數組
        memset(taken, 0, sizeof(taken));
       
        for(int i = 0; i < m; i++){
            int a, b, c, d, e;
            scanf("%d%d%d%d%d", &a, &b, &c, &d, &e);
            Node n1(a, b, c, d, e); 
            Node n2(b, a, c, d, e); //這裏jijkstra()算法算的是結構體
            v[a].push_back(n1); // v[a].push_back(n1); 從a出發到達的所有點的各種信息
            v[b].push_back(n2); // 雙向邊,反向建圖
        }
        dp[1] = 0; //第一個點先經歷 所以節點爲1
        for(int k = 0; k < n; k++){
            int min_dp = -1; // min_dp是最小值,最小加進來的
            for(int i = 1; i <= n; i++)
                if(!taken[i] && (min_dp == -1 || dp[i] < dp[min_dp]))
                    min_dp = i;
            taken[min_dp] = 1;  //選擇個最短的點 標記爲已經加入最短距離的數組中,接下來用來哦更新其它點
            for(int i = 0; i < v[min_dp].size(); i++){
                Node n = v[min_dp][i]; //這一個點,也就是軒主最小距離min_dp的下一個點
                if(dp[n.x]>=n.end || (dp[n.x]+n.val)<n.start)//暴風雨來臨前已經溜了或者暴風雨刮完了纔到
                    dp[n.y] = min(dp[n.y], dp[n.x] + n.val);
                else dp[n.y] = min(dp[n.y], n.end + n.val);//要等暴風雨結束才能走
            }
        }
        cout<< dp[n] + 1<< endl;//天數是從第一天開始算的 沒有第0天 所以加一
        
    }   
    return 0;
}

做個標記。挺經典的,圖論之重點算法

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