Graph
最短路徑問題
Relaxation
(a, b)
(a,b)
假設存在一條邊 ,邊權為
從起點到 兩點的路徑長分別為
在 的時候,就可以更新起點到 的路徑
W_{ab}
Wab
a, b
a,b
L_{a}, L_{b}
La,Lb
L_{a}+W_{ab} < L_{b}
La+Wab<Lb
b
b
Bellman-Ford Algorithm
- 單點源最短路徑
- 邊權可以是負數
- 如果一張圖沒有負環,那最短路徑最多只能包含 條邊,所以窮舉 次就好了
V-1
V−1
V-1
V−1
Dijkstra's Algorithm
- 單點源最短路徑
- 邊權都非負
- 有種 Prim's algorithm 的感覺
- 如果有一個部分完成的最短路徑樹,則加入目前離根最近而且不在樹上的點
- 複雜度
O(E log V)
O(ElogV)
int dis[V] = INF;
bool in_tree[V] = false;
void dijkstra(int source){
priority_queue<node> pq;
pq.push((node){dis[source] = 0, source});
while(!pq.empty()){
if(in_tree[pq.top().vertex]){
pq.pop();
continue;
}
now = pq.top().vertex;
for(int i = 0; i < edge[now].size(); i++){
next = edge[now][i];
if(dis[now]+weight(now, next) < dis[next]){
pq.push((node){dis[next] = dis[now]+weight(now, next), next});
}
}
}
}Floyd-Warshall Algorithm
-
全點對最短路徑
-
可以有負權
-
在一個路徑上,考慮一個一個中繼點,把「由 點中途經過前 點抵達 點的最短路徑長」拿來 DP,就得到轉移式:
-
複雜度
dp_{k,i,j} = min(dp_{k-1,i,k}+dp_{k-1,k,j}, dp_{k-1,i,j})
dpk,i,j=min(dpk−1,i,k+dpk−1,k,j,dpk−1,i,j)
i
i
k
k
j
j
O(V^{3})
O(V3)
int weight[V][V], dis[V][V];
void floyd_warshall(){
for(int i = 0; i < V; i++)
dis[i][i] = 0;
for(int k = 0; k < V; k++)
for(int i = 0; i < V; i++)
for(int j = 0; j < V; j++)
if(dis[i][j] > dis[i][k] + dis[k][j])
dis[i][j] = dis[i][k] + dis[k][j];
}Exercises
- TIOJ 1096
- TIOJ 1641
- TIOJ 1028
Graph
By hfy880916
Graph
- 470