【问题标题】:Floyd Warshall algorithm with maximum steps allowed允许最大步数的 Floyd Warshall 算法
【发布时间】:2014-06-19 23:48:24
【问题描述】:

在解决具有 n 个节点的有向加权图的最短路径问题时,是否可以修改 Floyd-Warshall 算法,使得每条最短路径的长度不超过 m 步骤?更准确地说,对于每一对节点 ij,你将要找到从 ij 包含不超过 m 个节点。时间复杂度是否仍然保持O(n3)?

【问题讨论】:

  • 我想不出一种方法可以在少于 O(n^3m^2) 的时间内完成。 (本质上:使用 DP 计算 f(i, j, k, w) 的每个值,其中该函数表示从 i 到 j 的最短路径,仅使用顶点
  • 我需要解决的问题很慢。最近,使用min-plus matrix multiplication,我实现了 m-edges all-pairs-shortest-paths 算法,在 O(n^3*log(n)) 时间内最大 m 个边。跨度>
  • 我很想看看你的方法——你能把它写下来作为答案吗? (这是允许的,甚至在 SO 上也是鼓励的。)我看不出如何避免使用这种方法将 m 作为运行时间的一个因素,因为每个矩阵乘法需要 O(n^3) 时间(或至少 O( n^2.something),你最多可能需要 m 个。即便如此,这仍然可以节省 m 个因素。
  • 实际上,如果您的意思是 O(n^3*log(m)),那么我可能会看到它是如何工作的:使用重复平方将最大迭代次数从 m 降低到 log m。那正确吗?写一篇文章仍然很棒:)
  • 是的,你是对的! :) 当然,我会写它作为答案。

标签: algorithm dynamic-programming shortest-path floyd-warshall


【解决方案1】:

同时,我发现了一个 O(n3logm) 算法来找到最短的所有对具有 n 个节点的图的路径(ASPP)问题,使得没有路径包含超过 m 个节点。

给定两个 n x n 矩阵,比如 A = [aij ] 和 B = [bij],他们的distance productn x n 矩阵 C = [cij] = A x B,定义为cij = min1≤k n {aik + b kj}。

这与 ASPP 有以下关系。给定图中距离的加权矩阵EEn是所有对最短路径的矩阵。如果我们添加约束,即没有路径包含超过 m 个节点,那么矩阵 Em 就是 ASPP 的解决方案.由于计算能力可以在 O(logm) 时间内找到,这给了我们一个 O(n3logm) 算法。

Here,在某些特殊情况下,可能会找到更快的算法来计算矩阵的距离积,但微不足道的一个O(n3 sup>) 对我来说已经足够了,因为总时间几乎与 Floyd-Warshall 方法一样快。

【讨论】:

  • 不错。起初我以为这只会使用 exactly m 边计算最短路径,但后来我意识到它使用恰好 m 个边 计算最短路径,其中任意数量的边可能是“ self-edges" 的成本为 0,因此它实际上使用 最多 m 条边计算所有最短路径 :)
【解决方案2】:

是的,是的。

  • 算法的每次迭代都会增加您搜索路径的单个长度单位。因此,如果您将迭代次数限制为 m,那么您会发现一条长度最多为 m 的路径。
  • 在 m -> n 的最坏情况下,复杂度将保持 O(n^3)。但是,更精确的估计应该是 O(m * n^2)。

【讨论】:

  • 我可能还没有搞定,如何将迭代限制为 m?你的意思是把第一行代码从for k = 1 to n do改成for k = 1 to m do?在这种情况下,正如您所说,复杂性降低了,但是在找到每对节点之间的最短路径时,只考虑图的前 m 个节点。
  • 啊抱歉,我在想贝尔曼福特算法似乎:en.m.wikipedia.org/wiki/Bellman%E2%80%93Ford_algorithm
【解决方案3】:

我相信这可以通过不同的数据结构(可以让您跟踪步数的数据结构)来完成?

由于 Floyd-Warshall 通常使用连接矩阵(其中矩阵 [j][k] 表示节点 j 和 k 之间的距离)来完成,因此我们可以不将该矩阵设为整数,而是将其设为具有两个整数的结构:两个节点之间的距离和它们之间的步数。

我用 C++ 写了一些东西来解释我的意思:

#define INFINITY 9999999

struct floydEdge
{
    int weight;
    int steps;
};

floydEdge matrix[10][10];

int main()
{
    //We initialize the matrix
    for(int j=0;j<10;j++)
    {
        for(int k=0;k<10;k++)
        {
            matrix[j][k].weight=INFINITY;
            matrix[j][k].steps=0;
        }
    }

    //We input some weights
    for(int j=0;j<10;j++)
    {
        int a, b;
        cin>>a>>b;
        cin>>matrix[a][b].weight;
        matrix[b][a].weight=matrix[a][b].weight;
        matrix[a][b].steps=matrix[b][a].steps=1;
    }

    //We do the Floyd-Warshall, also checking for the step count as well as the weights
    for(int j=0;j<10;j++)
    {
        for(int k=0;k<10;k++)
        {
            for(int i=0;i<10;i++)
            {
                //We check if there is a shorter path between nodes j and k, using the node i. We also check if that path is shorter or equal to 4 steps.
                if((matrix[j][k].weight > matrix[j][i].weight + matrix[i][k].weight) && (matrix[j][i].steps+matrix[i][k].steps<=4))
                {
                    matrix[j][k].weight=matrix[k][j].weight=matrix[j][i].weight + matrix[i][k].weight;
                    matrix[j][k].steps=matrix[k][j].steps=matrix[j][i].steps+matrix[i][k].steps;
                }
                //If the path is not shorter, we can also check if the path is equal BUT requires less steps than the path we currently have.
                else if((matrix[j][k].weight == matrix[j][i].weight + matrix[i][k].weight) && (matrix[j][i].steps+matrix[i][k].steps<matrix[j][k].steps))
                {
                    matrix[j][k].weight=matrix[k][j].weight=matrix[j][i].weight + matrix[i][k].weight;
                    matrix[j][k].steps=matrix[k][j].steps=matrix[j][i].steps+matrix[i][k].steps;
                }
            }
        }
    }
    return 0;
}

我相信(但我不完全确定)这可以完美地工作(总是为所有节点之间提供最短路径)。试试看,告诉我!

【讨论】:

  • 恐怕这不会一直给出最佳答案:对于某些顶点 j 和 k,即使通过 i 的最短路径需要超过 4 个(!)步,还有另一条通过 i 的路径,它需要 4 步或更少的步,但它仍然比 j 和 k 之间避免 i 的所有路径更好。
  • 例如假设有 6 个顶点 j=v1, v2, i=v3, v4, v5, k=v6,每个顶点和下一个顶点之间的边权重为 2,j 和 i 之间的边权重为 5,并且j 和 k 之间的权重为 12 的边。然后最短的 j->k 路径通过 i 并且有 5 条边,总权重为 10,但是这有太多边,所以你的算法将忽略它以及访问 i 的所有 j->k 路径,更喜欢最短的i-避免路径,即权重为12的单边j->k。但这忽略了总权重较低的4边路径j->i->v4->v5->k 11.
猜你喜欢
  • 1970-01-01
  • 2015-01-31
  • 2014-06-28
  • 1970-01-01
  • 2017-09-12
  • 2014-05-09
  • 2016-01-18
  • 2018-11-11
  • 1970-01-01
相关资源
最近更新 更多