Graph

最短路徑問題

Relaxation

(a, b)
(a,b)(a, b)

假設存在一條邊           ,邊權為          

從起點到         兩點的路徑長分別為              

在                              的時候,就可以更新起點到    的路徑

W_{ab}
WabW_{ab}
a, b
a,ba, b
L_{a}, L_{b}
La,LbL_{a}, L_{b}
L_{a}+W_{ab} < L_{b}
La+Wab<LbL_{a}+W_{ab} < L_{b}
b
bb

Bellman-Ford Algorithm 

  • 單點源最短路徑
  • 邊權可以是負數
  • 如果一張圖沒有負環,那最短路徑最多只能包含           條邊,所以窮舉            次就好了
V-1
V1V-1
V-1
V1V-1

Dijkstra's Algorithm

  • 單點源最短路徑
  • 邊權都非負
  • 有種 Prim's algorithm 的感覺
  • 如果有一個部分完成的最短路徑樹,則加入目前離根最近而且不在樹上的點
  • 複雜度
O(E log V)
O(ElogV)O(E log V)
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(dpk1,i,k+dpk1,k,j,dpk1,i,j)dp_{k,i,j} = min(dp_{k-1,i,k}+dp_{k-1,k,j}, dp_{k-1,i,j})
i
ii
k
kk
j
jj
O(V^{3})
O(V3)O(V^{3})
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
Made with Slides.com