<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                # 圖的最短路徑 ## Dijkstra 算法 適用于無負權圖的單源最短路徑問題,復雜度為 $$O(V^2+E)$$ ### 最短距離 #### 偽碼 ```c++ // 數組 d[] 為源點 s 到達各點的最短路徑長度 Dijkstra(G, d[], s){ 初始化; for(循環 n 次){ u=使 d[u] 最小的還未被訪問的頂點標號; 記 u 已被訪問; for(從 u 出發所有能到達的頂點 v){ if(v 未被訪問 && 以 u 為中介點使 s 到頂點 v 的最短距離 d[v] 更優) 優化 d[v]; } } } ``` #### 鄰接矩陣 ```c++ const int maxv=1000; const int inf=0x3fffffff; int n,G[maxv][maxv]; int d[maxv]; bool vis[maxv]={false}; void Dijkstra(int s){ // 初始化 fill(d,d+maxv,inf); d[s]=0; for(int i=0;i<n;i++){ // 查找使 d[u] 最小的還未被訪問的頂點標號 u int u=-1,min=inf; for(int j=0;j<n;j++){ if(vis[j]==false && d[j]<min){ u=j; min=d[j]; } } // 找不到滿足條件的 u if(u==-1) return; // 標記 u 已被訪問; vis[u]=true; // 優化 vis 集到 u 所能到達的為被訪問的頂點的距離 for(int v=0;v<n;v++){ if(vis[v]==false && G[u][v]!=inf && d[u]+G[u][v]<d[v]) d[v]=d[u]+G[u][v]; } } } ``` #### 鄰接表 ```c++ const int maxv=1000; const int inf=0x3fffffff; int n; int d[maxv]; bool vis[maxv]={false}; struct Node{ int v,dis; }; vector<Node> Adj[maxv]; void Dijkstra(int s){ fill(d,d+maxv,inf); d[s]=0; for(int i=0;i<n;i++){ int u=-1,min=inf; for(int j=0;j<n;j++){ if(vis[j]==false && d[j]<min){ u=j; min=d[j]; } } if(u==-1) return; vis[u]=true; for(int j=0;j<Adj[u].size();j++){ int v=Adj[u][j].v; if(vis[v]==false && d[u]+Adj[u][j].dis<d[v]) d[v]=d[u]+Adj[u][j].dis; } } } ``` ### 最短路徑 #### 偽碼 在求最短距離偽碼的 `優化 d[v];` 之后,加上 `令 v 的前驅為 u;` ```c++ // 數組 d[] 為源點 s 到達各點的最短路徑長度 Dijkstra(G, d[], s){ 初始化; // 初始化令每個節點的前驅為自身 for(循環 n 次){ u=使 d[u] 最小的還未被訪問的頂點標號; 記 u 已被訪問; for(從 u 出發所有能到達的頂點 v){ if(v 未被訪問 && 以 u 為中介點使 s 到頂點 v 的最短距離 d[v] 更優){ 優化 d[v]; 令 v 的前驅為 u; // 僅此處改動 } } } } ``` #### 鄰接表 ```C #define MAXV 500 #define INF 999999 typedef int ElemType; typedef struct { int no; // 頂點編號 ElemType info; // 頂點其他信息 }VertexType; // 聲明頂點類型 typedef struct { int edges[MAXV][MAXV]; // 鄰接矩陣 int n, e; // 定點數和邊數 VertexType vexs[MAXV]; // 存放頂點信息 }MGraph; // 聲明圖的鄰接矩陣類型 // 初始化圖的鄰接矩陣 void CreateMat(MGraph &g, int A[][MAXV], int n) { // 由數組 A[n][n] 生成鄰接矩陣 g int i, j; g.n = n; g.e = 0; for(i=0; i<g.n; i++){ for(j=0; j<g.n; j++){ g.edges[i][j] = A[i][j]; if(g.edges!=0) g.e++; } } } // 迪克斯特拉算法 void Dijkstra(MGragh g, int v) { int dist[MAXV]; // U 集合中的各節點到 v 的最短距離 int path[MAXV]; // 用于記錄最短路徑中每一節點的前一節點 int S[MAXV]; // 已訪問集合 int mindist, i, j, u; // 將源點歸入 S 集合,其余節點歸入 U 集合 // 初始化 U 集合中各節點到 S 集合的距離 // 將與 S 集合相連的節點的路徑中的前一節點標記為源節點 for(i=0; i<g.n; i++){ S[i] = 0; dist[i] = g.edges[v][i]; if(g.edges[v][i]<INF) path[i] = v; else path[i] = -1; } S[v] = 1; for(i=0; i<g.n; i++){ // 在 U 集合中找出距離 S 集合最近的節點 mindist = INF; for(j=0; j<g.n; j++){ if(!S[j] && dist[j]<mindist){ mindist = dist[j]; u = j; } } S[u] = 1; // 將 u 點加入到 S 中 // 修改 U 集合中各節點到 v 的最短距離 for(j=0; j<g.n; j++){ if(g.edges[u][j]<INF && dist[u]+g.edges[u][j]<dist[j]){ dist[j] = dist[u] + g.edges[u][j]; path[j] = u; } } } DispAllPath(g, dist, path, S, v); } void DispAllPath(MGraph g, int dist[], int path[], int S[], int v) { int i, j, k; int apath[MAXV], d; for(i=0; i<g.n; i++){ if(S[i] && i!=v){ printf("The shortest path from %d to %d is %d:", v, i, dist[i]); d = 0; apath[d] = i; k = path[i]; if(k==-1) printf("None\n"); else{ while(k!=v){ d++;apath[d] = path[k]; k = path[k]; } d++; apath[d] = v; printf("%d", apath[d]); for(j=d-1; j>=0; j--) printf("-->%d", apath[j]); printf("\n"); } } } } ``` ### 求所有最短路徑 將 `pre[maxv]` 換成 `vector<int> pre[maxv]` ```c++ vector<int> pre[maxn]; void Dijkstra(int s){ fill(d,d+maxv,inf); d[s]=0; for(int i=0;i<n;i++){ int u=-1,min=inf; for(int j=0;j<n;j++){ if(vis[j]==false && d[j]<min){ min=d[j]; u=j; } } if(u==-1) return; vis[u]=true; for(int v=0;v<n;v++){ if(vis[v]==false && G[u][v]!=inf){ if(d[u]+G[u][v]<d[v]){ d[v]=d[u]+G[u][v]; pre[v].clear(); pre[v].push_bakc(u); }else if(d[u]+G[u][v]==d[v]){ pre[v].push_bakc(u); } } } } } ``` ### 第二標尺 第一標尺是路徑長度,有時題目還會有第二標尺。 ## Bellman-Ford 算法與 SPFA 算法 復雜度為 $$O(VE)$$ ### 最短距離 ```c++ // 鄰接表 struct Node{ int v, dis; }; vector<Node> Adj[maxn]; int n; int d[maxn]; bool Bellman(int s){ fill(d,d+maxn,inf); d[s]=0; // 求解數組 d for(int i=0;i<n-1;i++){ for(int u=0;u<n;u++){ for(int j=0;j<n;j++){ int v=Adj[u][j].v; int dis=Adj[u][j].dis; if(d[u]+dis<d[v]) d[v]=d[u]+dis; } } } // 判斷負環 for(int u=0;u<n;u++){ for(int j=0;j<Adj[u].size();j++){ int v=Adj[u][j].v; int dis=Adj[u][j].dis; if(d[u]+dis<d[v]) return false; } } return true; } ``` ### 最短路徑條數 因為該算法會反復累計已經算過的頂點,設置記錄前驅的數組 `set<int> pre[maxv];` ,遇到一條與已有最短路徑長度相同的路徑時,重新計算最短路徑條數。 ```c++ // ... else if(d[u]+dis==d[v]){ pre[v].insert(u); num[v]=0; set<int>:: iterator it; for(it=pre[v].begin();it!=pre[v].end();it++){ num[v]+=num[*it]; } } ``` ### SPFA (Shortest Path Faster Algorithm) 在 Bellman-Ford 算法,每次都要訪問所有邊,而實際上只有當某個頂點 u 的 d[u] 值改變時,從它出發的鄰接點 v 的 d[v] 值才會改變。對此進行優化,得到 SPFA。 #### 偽碼 ```c++ queue<int> q; 源點 s 入隊; while(q非空){ for(u 的所有鄰接邊 u->v){ if(d[u]+dis<d[v]){ d[v]=d[u]+dis; if(v 當前不再隊列){ v 入隊; if(v 入隊次數大于 n-1) 說明有可達負環, return; } } } } ``` #### 鄰接表 ```c++ vector<Node> Adj[maxv]; int n, d[maxv],num[maxv]; // num 記錄頂點的入隊次數 bool inq[maxv]; bool SPFA(int s){ // 初始化 memset(inq,false,sizeof(inq)); memset(num,0,sizeof(num)); fill(d,d+maxv,inf); // 源點入隊 queue<int> q; q.push(s); inq[s]=true; num[s]++; d[s]=0; // 主體 while(!q.empty()){ int u=q.front(); q.pop(); inq[u]=false; // 遍歷 u 的所有鄰接邊 v for(int j=0;j<Adj[u].size();j++){ int v=Adj[u][j].v; int dis=Adj[u][j].dis; if(d[u]+dis<d[v]){ d[v]=d[u]+dis; if(!inq[v]){ q.push(v); inq[v]=true; num[v]++; if(num[v]>=n) return false; } } } } return true; } ``` ## Floyd 算法 適用于解決全源最短路徑問題,時間復雜度為 $$O(V^3)$$ ### 偽碼 ```c++ 枚舉頂點 k in [1,n]; 以頂點為中介點,枚舉所有頂點對 i,j in [1,n] if(dis[i][k]+dis[k][j]<dis[i][j]) dis[i][j]=dis[i][k]+dis[k][j]; ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看