dijkstral演算法適用於無負權邊的圖。
圖結構和輔助陣列
const
int inf =
0x3fffffff
;// inf定義為了int的上限
// cost為邊權矩陣; weight為點權,若有則可以使用
int g[maxn]
[maxn]
, cost[maxn]
[maxn]
, weight[maxn]
;// weight_cal若題目中要求點權的累計最大則可使用 cost_cal若題目中要求邊權累計最大則可以使用
int dist[maxn]
, weight_cal[maxn]
, cost_cal[maxn]
;int path_num[maxn]
;// 路徑條數
bool visited[manx]
;vector<
int> path[maxn]
;// 求具體路徑可以使用
演算法模板(基於貪心思想)
void
dijkstral
(int start_node)}if
(u ==-1
)break
; visited[u]
=true
;// 更新距離
for(
int v =
0; v < n; v++
)else
if( dist[v]
== dist[u]
+ g[u]
[v])
// if..else if..
}// if
}// for...
}}
若是嫌麻煩, 先用dijkstarl模板求出所有具體最短路徑,再用dfs來求解題目所需要的那條路徑
vector<
int> temp, best_path;
void
dfs(
int u,
int start_node)
else
} temp.
pop_back()
;// 退出該節點
}
鄰接表形式適用於maxn大的情況,一般大於1000可以考慮使用鄰接表。
借助stl中的vector容器可以定義圖結構
struct node
vector g[maxn]
;
dijkstarl演算法(改動很小)
void
dijkstral
(int start_node)}if
(u ==-1
)break
; visited[u]
=true
;// 更新距離
for(
auto it : g[u]
)else
if( dist[v]
== dist[u]
+ g[u]
[v])
// if .. else if ..
}// if ..
}// for ..
}// for ...
}
當鄰接表形式的dikstral演算法無法滿足時間複雜度時,可以考慮使用堆優化來優化該演算法。堆優化的本質是用小根堆的性質來代替下面這段**
int u =-1
, max_d = inf;
for(
int j =
0; j < n; j++
)}
若手動建堆並每次刪除維護,可以檢視我的堆模板,使用downadjust和insert來維護堆。
在stl中提供了好用的優先佇列priority_queue, 可以用它來代替堆並讓stl自動幫我們維護
定義節點結構,並且過載小於號<
struct node
;// 建構函式 可以不寫
friend
bool
operator
<
(node a, node b)
// 過載了 小於號 <
/* bool operator < (const node& a) const
*/// 這種寫法也可以過載小於號, 認準一種就行
};
堆優化的演算法
void
dijkstral
(int start)
}/* 臨界矩陣版本
for (int v = 0; v < n; v++)
}} */
}}
在pat中基本使用dijkstral演算法即可滿足題目要求,但如果題目出現負權邊,我們可以使用bellman ford演算法和spfa演算法,但bellman ford的時間複雜度相對於spfa通常會來的更高些,必將spfa優化bellman ford演算法了,因此推薦使用spfa圖定義和一些相關的輔助陣列
struct node
;vector g[maxn]
;int num[maxn]
, dist[maxn]
;bool inq[maxn]
;
spfa演算法返回bool值,返回true代表沒用負權變,false代表有負權變對於有源點可達負權環的圖,dijkstral可能會失效,如下所示
dist陣列和visited陣列的情況如下(s為源點)頂點s
abcdist05
infinf
visited
true
true
false
false
通過貪心策略更新dist陣列頂點
sabc
dist05
46visited
true
true
false
false
然後會選擇b頂點作為下乙個頂點並訪問它頂點s
abcdist05
46visited
true
true
true
false
然後貪心更新dist陣列(b不可到達c)頂點s
abcdist05
46visited
true
true
true
false
最後訪問c頂點s
abcdist05
46visited
true
true
true
true
因此s到b的最短路徑是4,但實際可以發現最短路徑應該是a->c->b,距離為5+1-5 = 1
spfa的思想其實很簡單;
從某個源點出發到各個點的最短路徑若存在一定會產生一棵最短路徑樹。
有兩種最極端的情況,一種是這棵樹的高度只有2層,即源點直接到所有點有路徑且最短;另一種則是樹的高度為n,類似於了一根鍊錶。
現在考慮第一種情況,當最短路徑存在時,訪問次數最多的一定是源點,並且訪問次數應該小於等於n-1次(通過該點去更新相鄰點)。
因此我們並不設定visited陣列,讓頂點的訪問可以是無限次。然後每一次訪問頂點後更新dist陣列,並且將該頂點的訪問次數加1
由於負權環的存在,每次選擇頂點會反覆選擇負邊環上的頂點,因此負邊上的頂點會反覆出現。當出現次數大於等於n時,我們就可以認為存在負邊環。
// spaf最短路徑演算法
bool
spfa
(int start)}}
}return
true
;}
演算法題 最短路徑 03 最短路
在每年的校賽裡,所有進入決賽的同學都會獲得一件很漂亮的t shirt。但是每當我們的工作人員把上百件的衣服從商店運回到賽場的時候,卻是非常累的!所以現在他們想要尋找最短的從商店到賽場的路線,你可以幫助他們嗎?input 輸入包括多組資料。每組資料第一行是兩個整數n m n 100,m 10000 n...
最短路徑演算法 最短路
在每年的校賽裡,所有進入決賽的同學都會獲得一件很漂亮的t shirt。但是每當我們的工作人員把上百件的衣服從商店運回到賽場的時候,卻是非常累的!所以現在他們想要尋找最短的從商店到賽場的路線,你可以幫助他們嗎?input 輸入包括多組資料。每組資料第一行是兩個整數n m n 100,m 10000 n...
刷題 最短路 猴子
很神奇的轉換 有n只猴子,第一只尾巴掛在樹上,剩下的n 1只,要麼被其他的猴子抓住,要麼抓住了其他的猴子,要麼兩者均有。當然乙隻猴子最多抓兩隻另外的猴子。現在給出這n只猴子抓與被抓的資訊,並且在某個時刻可能某只猴子會放掉它其中乙隻手的猴子,導致某些猴子落地。求每只猴子落地的時間。luogu大佬原話 ...