航線–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
算法思想:
- 在這裏用臨界矩陣作爲鄰接表存儲每一個節點的信息,由於信息很多,所以不考慮用pair<>而考慮用臨界節點Node來存儲所有的節點信息。
- 若行船時間要與風暴時間有重合需要等到暴風雨結束才能出發
如果還不是很理解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;
}
做個標記。挺經典的,圖論之重點算法