# 最短路徑 ---- ## 術語 ---- ## 負邊 權重為負的邊 ---- ## 負環 權重和為負的環 ---- ## 點源(Source) 成為起點的點,分成單源頭(Single Source)及多源頭(Multiple Source)。 ---- ## 鬆弛(Relax) 現在要找尋起點為 s 、終點為 t 的最短路徑,而且現在已經有一條由 s 到 t 的路徑,這條路徑上會依序經過 a 及 b 這兩點(可以是起點和終點)。我們可以找到一條新的捷徑,起點是 a 、終點是 b 的捷徑,以這條捷徑取代原本由 a 到 b 的這一小段路徑,讓路徑變短。 ---- ## 單點源最短路徑(Single Source) ---- ## Dijkstra's Algorithm ---- * 把離樹根最近的點加入最短路徑樹裡 * 並把所有與該點相連的邊鬆弛 * 已經加入的點不會在被鬆弛 * 使用priority_queue的複雜度為$O((V+E)logE)$ * [example](http://nthucad.cs.nthu.edu.tw/~yyliu/personal/nou/04ds/dijkstra.html) ---- * $d[n]$ 到n的距離 * $edge[node.from][node.to]$ $node.from$ 與 $node.to$ 之間的邊長度 ```cpp= if(d[node.to] > d[node.from] + edge[node.from][node.to]){ d[node.to] = d[node.from] + edge[node.from][node.to]; q.push({node.to,d[node.to]}); } ``` ---- ```cpp= struct edge{ int from,to,w; }; struct Node{ int node,dist; P(int _node,int _dist){ node = _node; dist = _dist; } bool operator<(const P& rhs)const{//權重較小的邊與點源距離較大 return dist > rhs.dist; } }; vector<edge>edges; vector<int>G[20001]; int d[20001],Case,n,m,s,e,from,to,w,cnt; void addedge(int from,int to, int w){//建雙向邊 edges.push_back({from,to,w}); edges.push_back({to,from,w}); int m = edges.size(); G[from].push_back(m-2);//存與from相連的邊在edges的index G[to].push_back(m-1); } bool vis[20001];//是否拜訪過 void init(){ edges.clear(); for(int i=0;i<20001;i++){ G[i].clear(); d[i] = inf;//距離皆設無限大 vis[i] = false; } d[s] = 0;//起點距離為0 } void dijkstra(){ priority_queue<Node>q; q.push(Node(s,d[s])); while(!q.empty()){ auto x = q.top();q.pop(); if(x.node == e)break; if(vis[x.node])continue;//已經拜訪過則skip vis[x.node] = true; for(auto it:G[x.node]){//找與G[x.node]相鄰點的index auto edge = edges[it];// if(d[edge.to] > d[edge.from] + edge.w){ d[edge.to] = d[edge.from] + edge.w; q.push({edge.to,d[edge.to]}); } } } } ``` ---- [遇到負邊會發生甚麼事?](https://www.itread01.com/content/1548100475.html) ---- ## 題單 * [uva 929](https://onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=24&page=show_problem&problem=870) * [uva 10986](https://onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=24&page=show_problem&problem=1927) ---- ## [Bellman–Ford algorithm](https://ithelp.ithome.com.tw/articles/10209748) ---- 因為拜訪過就不考慮進去 ---- 那麼就... ---- 不管你有沒有拜訪過都考慮進去 ---- * 單點源最短路徑 * 對所有邊枚舉,執行V-1輪(因為最短路徑上最遠的兩個點經過V-1條邊),複雜度為$O(VE)$ * 如果執行第V次時還有邊可以鬆弛,代表有負環 * [example](https://www.geeksforgeeks.org/bellman-ford-algorithm-dp-23/) ---- ```cpp= void bellman_ford(int s){ d[s]=0; p[s]=s; for(int i=0;i<V-1;i++){//進行V-1次鬆弛 for(int ss=0;ss<V;ss++){ for(auto tt:v[ss]){//與ss相連的邊 if(d[ss]+w[ss][tt]<d[tt]){ d[tt]=d[ss]+w[ss][tt]; p[tt]=ss; } } } } } bool has_negative_cycle(){ for(int i=0;i<V;i++){ for(int j=0;j<V;j++){ if(d[i]+w[i][j]<d[j])return true; } } return false; } ``` ---- ## 題單 * [uva 558](https://onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=24&page=show_problem&problem=499) * [uva 10449](https://onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=24&page=show_problem&problem=1390) ---- [先備知識](https://www.itread01.com/content/1547221357.html) ---- ## [Floyd Warshall Algorithm](https://ithelp.ithome.com.tw/articles/10209186) ---- **求任意兩點之間最短路徑** ---- 概念:因為每一個點都有可能使另外兩個點之間的路徑變的更短,所以就把所有的點當作中間點枚舉 ---- ## DP式 * 狀態:$dp[k][i][j]$ 代表,若只以點 1到k 當中繼點的話,則 $dp[k][i][j]$ 為 i 到 j 的最短路徑長。 * 轉移:$dp[k][i][j]$ = min($dp[k-1][i][k]$ + $dp[k-1][k][j]$, $dp[k-1][i][j]$) * 基底: $dp[0][i][j]$ = $w[i][j]$ if $w[i][j]$ exists INF else ---- ```cpp= for (k = 0; k < n; k++)//枚舉中間點 for (i = 0; i < n; i++)//枚舉起點 for (j = 0; j < n; j++)//枚舉終點 w[k][i][j] = min(w[k-1][i][j], w[k-1][i][k] + w[k-1][k][j]);//雙向邊 w[i][j] = w[j][i] = min(w[i][j], w[i][k] + w[k][j]);//單向邊 ``` ---- * 時/空間複雜度皆為$O$(V^3^) * 滾動陣列 * 空間複雜度可降為$O$(V^2^) ---- ## 空間壓縮 ```cpp= for (k = 0; k < n; k++)//枚舉中間點 for (i = 0; i < n; i++)//枚舉起點 for (j = 0; j < n; j++)//枚舉終點 w[i][j] = min(w[i][j], w[i][k] + w[k][j]);//雙向邊 w[i][j] = w[j][i] = min(w[i][j], w[i][k] + w[k][j]);//單向邊 ``` ---- $dp[i][j]<0$ 代表存在負環
{"metaMigratedAt":"2023-06-15T04:35:02.035Z","metaMigratedFrom":"Content","title":"最短路徑","breaks":true,"contributors":"[{\"id\":\"d7432ba6-f741-4fe8-aa32-d87a2785be72\",\"add\":4888,\"del\":567}]"}
    360 views