zoukankan      html  css  js  c++  java
  • Folyd + 路径存储

    一、Folyd 算法原理

      

    1. 如果 AB + AC < BC 那么, BC最短路就要经过 A。 在算法进行过程中,应该是 B-A 有很多路径,B 代表这些路径权值之和,A-C也有很多路径,C是这些权值之和。那么我们找到一个 满足  AB + AC < BC 的时候更新权值数组,并且记录路径。
    2. dist[i][j] = k 表示,从 I -- J 点的路径权值为 K

    3. 记录路径,就是将 C 点连接在 B A C 这样的路径后  

    二、简单容易理解版

    核心代码:

     1 //邻接矩阵保存点信息
     2 int mapp[MAX_POINT][MAX_POINT];
     3 //保存任意两点之间的最短路径上的节点
     4 vector<int> trace_path[MAX_POINT][MAX_POINT];
     5 
     6 void Folyd(int n) {
     7     for (int k = 0; k < n; k++)
     8         for (int i = 0; i < n; i++)
     9             for (int j = 0; j < n; j++)
    10                 if (mapp[i][j] > mapp[i][k] + mapp[k][j]) {
    11                     mapp[i][j] = mapp[i][k] + mapp[k][j];
    12                     trace_path[i][j].clear();
    13                     //放入 i---k 路径节点
    14                     for (int z = 0; z < trace_path[i][k].size(); z++)
    15                         trace_path[i][j].push_back(trace_path[i][k][z]);
    16                     //放入 k---j 路径节点
    17                     for (int z = 0; z < trace_path[k][j].size(); z++)
    18                         trace_path[i][j].push_back(trace_path[k][j][z]);
    19                 }
    20 }
    21 
    22 void query(int from, int to) {
    23     cout << "from " << from << " to " << to << " should cost " << mapp[from][to] <<"."<< endl;
    24     cout << "trace_path: " ;
    25     for (int i = 0; i < trace_path[from][to].size(); i++)
    26         cout<< trace_path[from][to][i] << " -> ";
    27     cout << to << endl;
    28 }
    View Code

     上述代码中:存在重复存储,效率极低

    1 trace_path[i][j].clear();
    2 //放入 i---k 路径节点
    3 for (int z = 0; z < trace_path[i][k].size(); z++)
    4     trace_path[i][j].push_back(trace_path[i][k][z]);
    5 //放入 k---j 路径节点
    6 for (int z = 0; z < trace_path[k][j].size(); z++)
    7     trace_path[i][j].push_back(trace_path[k][j][z]);
    View Code

     优化代码:

    由于上面代码每次都重复把点的信息都保存下来,因此,我们采用保存前驱几点的方式,最终通过回溯构建路径。

    path[i][j] = k ; //表示 从 i---j 路径中, k 是 j 的直接前驱, 那么最短路径 1->5->4->3->6 有 paht[1][6] = 3; paht[1][3]= 4; paht[1][4] = 5; paht[1][5] =1 如此逆推不难得到 最短路径记录值

    核心代码:

     1 //邻接矩阵保存点信息
     2 int mapp[MAX_POINT][MAX_POINT];
     3 //path[i][j] = k ,表示从 i 到 j 最短路, k 邻接到j。
     4 int path[MAX_POINT][MAX_POINT];
     5 void Folyd(int n) {
     6     //初始化路径数组
     7     for (int i = 0; i < n; i++)
     8         for (int j = 0; j < n; j++) {
     9             if (mapp[i][j] - INF)
    10                 path[i][j] = i;
    11             else
    12                 path[i][j] = NOTEXISTS;
    13         }
    14 
    15     for (int k = 0; k < n; k++)
    16         for (int i = 0; i < n; i++)
    17             for (int j = 0; j < n; j++)
    18                 if (mapp[i][j] > mapp[i][k] + mapp[k][j]) {
    19                     mapp[i][j] = mapp[i][k] + mapp[k][j];
    20                     //path[i][j] = k; //这种思路中,不能写成这样
    21                     path[i][j] = path[k][j];
    22                 }
    23 }
    24 
    25 void print_path(int from, int to) {
    26     if (path[from][to] != from)
    27         print_path(from, path[from][to]);
    28     cout << " -> " << to;
    29 }
    View Code

     在更改权值的时候,即使记录下来当前点的前驱节点。 path[i][j] = path[k][j]; 切不可以写成,path[i][j] = k;  后者是另一种思路,下面会描述。path[i][j] = path[k][j] 达到 j 节点 的前驱节点修改为经过k到j的路径上去。

    完整代码:

    测试数据:

     1 8
     2 0 5 2
     3 0 3 4
     4 0 4 1
     5 1 5 8
     6 1 3 3
     7 2 4 6
     8 2 6 3
     9 1 7 2
    10 -1 0 0
    View Code

     

    1. 基础版本 

     1 //Folyd
     2 #include <iostream>
     3 #include <vector>
     4 #include <algorithm>
     5 
     6 using namespace std;
     7 
     8 const int INF = 0x3f3f3f3f;
     9 const int MAX_POINT = 10;
    10 
    11 //邻接矩阵保存点信息
    12 int mapp[MAX_POINT][MAX_POINT];
    13 //保存任意两点之间的最短路径上的节点
    14 vector<int> trace_path[MAX_POINT][MAX_POINT];
    15 
    16 void Folyd(int n) {
    17     for (int k = 0; k < n; k++)
    18         for (int i = 0; i < n; i++)
    19             for (int j = 0; j < n; j++)
    20                 if (mapp[i][j] > mapp[i][k] + mapp[k][j]) {
    21                     mapp[i][j] = mapp[i][k] + mapp[k][j];
    22                     trace_path[i][j].clear();
    23                     //放入 i---k 路径节点
    24                     for (int z = 0; z < trace_path[i][k].size(); z++)
    25                         trace_path[i][j].push_back(trace_path[i][k][z]);
    26                     //放入 k---j 路径节点
    27                     for (int z = 0; z < trace_path[k][j].size(); z++)
    28                         trace_path[i][j].push_back(trace_path[k][j][z]);
    29                 }
    30 }
    31 
    32 void query(int from, int to) {
    33     cout << "from " << from << " to " << to << " should cost " << mapp[from][to] <<"."<< endl;
    34     cout << "trace_path: " ;
    35     for (int i = 0; i < trace_path[from][to].size(); i++)
    36         cout<< trace_path[from][to][i] << " -> ";
    37     cout << to << endl;
    38 }
    39 
    40 int main(int argc, char const *argv[])
    41 {
    42     int n;
    43     cout << "Please input gragh points:";
    44     cin >> n;
    45     //init container, 自己到自己默认 0,其他为 INF
    46     for (int i = 0; i < n; i++) {
    47         mapp[i][i] = 0;
    48         for (int j = 0; j < n; j++)
    49             if (i != j)
    50                 mapp[i][j] = INF;
    51     }
    52 
    53 
    54     int t = (n*(n - 1)) >> 1;
    55     // 最多输入 n(n -1)>>1 条边
    56     cout << "Please input edges format a tuple (f, t , v), to end input via (-1, 0, 0)" << endl;
    57     while (--t > 0) {
    58         int from, to, value;
    59         cin >> from >> to >> value;
    60         if (~from) {
    61             //无向图
    62             mapp[from][to] = value;
    63             mapp[to][from] = value;
    64             //每条路的前驱放入路径中
    65             trace_path[from][to].push_back(from);
    66             trace_path[to][from].push_back(to);
    67         }
    68         else
    69             break;
    70     }
    71     
    72     Folyd(n);
    73 
    74     //结果打表
    75     cout << "====================" << endl;
    76     for (int i = 0; i < n; i++) {
    77         
    78         for (int j = 0; j < n; j++)
    79             cout << mapp[i][j] << "	";
    80         cout << endl;
    81     }
    82     cout << "====================" << endl;
    83      while(1){
    84          int beginP, endP;
    85          cout << "Please input begin point and end point:";
    86          cin >> beginP >> endP;
    87          query(beginP, endP);
    88      }
    89     return 0;
    90 }
    View Code

    2. 改进版本

     1 //Folyd
     2 //输入图,可以不连通
     3 #include <iostream>
     4 using namespace std;
     5 
     6 const int INF = 0x3f3f3f3f;
     7 const int MAX_POINT = 10;
     8 const int NOTEXISTS = ~(0U);
     9 
    10 //邻接矩阵保存点信息
    11 int mapp[MAX_POINT][MAX_POINT];
    12 //path[i][j] = k ,表示从 i 到 j 最短路, k 邻接到j。
    13 int path[MAX_POINT][MAX_POINT];
    14 void Folyd(int n) {
    15     //初始化路径数组
    16     for (int i = 0; i < n; i++)
    17         for (int j = 0; j < n; j++) {
    18             if (mapp[i][j] - INF)
    19                 path[i][j] = i;
    20             else
    21                 path[i][j] = NOTEXISTS;
    22         }
    23 
    24     for (int k = 0; k < n; k++)
    25         for (int i = 0; i < n; i++)
    26             for (int j = 0; j < n; j++)
    27                 if (mapp[i][j] > mapp[i][k] + mapp[k][j]) {
    28                     mapp[i][j] = mapp[i][k] + mapp[k][j];
    29                     path[i][j] = path[k][j];
    30                 }
    31 }
    32 
    33 void print_path(int from, int to) {
    34     if (path[from][to] != from)
    35         print_path(from, path[from][to]);
    36     cout << " -> " << to;
    37 }
    38 
    39 int main(int argc, char const *argv[])
    40 {
    41     int n;
    42     cout << "Please input gragh points:";
    43     cin >> n;
    44 
    45     //init container
    46     for (int i = 0; i < n; i++) {
    47         mapp[i][i] = 0; //自己到自己默认 0
    48         for (int j = 0; j < n; j++)
    49             if (i != j)
    50                 mapp[i][j] = INF;
    51     }
    52 
    53     int t = (n*(n - 1)) >> 1;
    54     // 最多输入 n(n -1)>>1 条边
    55     cout << "Please input edges format a tuple (f, t , v), to end input via (-1, 0, 0)" << endl;
    56     while (--t > 0) {
    57         int from, to, value;
    58         cin >> from >> to >> value;
    59         if (~from) {
    60             mapp[from][to] = value;
    61             mapp[to][from] = value;
    62         }
    63         else
    64             break;
    65     }
    66     Folyd(n);
    67 
    68     cout << "====================" << endl;
    69     for (int i = 0; i < n; i++) {
    70 
    71         for (int j = 0; j < n; j++)
    72             cout << mapp[i][j] << "	";
    73         cout << endl;
    74     }
    75     cout << "====================" << endl;
    76     while (1) {
    77         int beginP, endP;
    78         cout << "Please input begin point and end point:";
    79         cin >> beginP >> endP;
    80         //print path
    81         cout << "from " << beginP << " to " << endP << " should cost " << mapp[beginP][endP] << "." << endl;
    82         if (path[beginP][endP] == NOTEXISTS)
    83             cout << "No path!" << endl;
    84         else {
    85             cout << "trace_path: ";
    86             cout << beginP;
    87             print_path(beginP, endP);
    88             cout << endl;
    89         }
    90     }
    91     return 0;
    92 }
    View Code

    参考资料:

    https://blog.csdn.net/start0609/article/details/7779042

    https://blog.csdn.net/immiao/article/details/22199939

  • 相关阅读:
    LSTM
    Realsense D435i
    ubuntu18 realsenseD435i
    net
    test
    LSTM Accuracy
    boost x64 lib
    E0443类模板 "std::unordered_set" 的参数太多
    PropertySheet
    freetype 编译
  • 原文地址:https://www.cnblogs.com/TianyuSu/p/9122106.html
Copyright © 2011-2022 走看看