如何在有向图和线性时间中找到两个顶点之间不同最短路径的数量?

时间:2012-04-19 10:33:14

标签: algorithm data-structures graph breadth-first-search

以下是练习:

  

令v和w为有向图G =(V,E)中的两个顶点。设计线性时间算法以找到v和w之间的不同最短路径(不一定是顶点不相交)的数量。注意:G中的边是未加权的


对于这个消费税,我总结如下:

  1. 这是有向图
  2. 它要求不同最短路径的数量。首先,路径应该是最短的,然后可能有不止一条这样的最短路径,其长度是相同的。
  3. 介于v和w之间,因此从v到w以及从w到v都应计算在内。
  4. 线性时间。
  5. 图表未加权。

  6. 从以上几点来看,我有以下想法:

    1. 我不需要使用Dijkstra’s Algorithm因为图表没有加权,我们会尝试找到所有最短路径,而不仅仅是单个路径。
    2. 我为最短路径的数量维持count
    3. 我想首先使用BFS并保留global level信息
    4. 我每次将global level增加1,然后BFS达到新的水平
    5. 我还保留shortest level信息以获取最短路径
    6. 我第一次在旅行时遇到w,我将global level分配给shortest levelcount++;
    7. 只要global level等于shortest level,我每次见到w时都会增加count
    8. 如果global level变得大于shortest level,我会终止旅行,因为我正在寻找最短路径而不是路径。
    9. 然后我再次做2 - 8,为了w

    10. 我的算法是否正确?如果我做v然后w到v,那还是被认为是线性时间吗?

8 个答案:

答案 0 :(得分:20)

以下是对此的一些看法。

  • 从v-> w到节点x只能存在多条最短路径,无论是通过相同的顶点有多条路径进入x,还是在同一DFS级别多次遇到x。

证明:如果有多条路径通过相同的顶点进入x,那么x显然有多种方式。这很简单。现在让我们假设x通过每个顶点进入x(最多)只有一种方法。

如果之前遇到过x,则当前路径都不会对另一条最短路径产生影响。由于之前遇到过x,所以可以跟随的所有路径将比前一个最短路径长至少一个。因此,这些路径都不能对总和做出贡献。

这意味着我们最多只遇到一次节点并完成。所以正常的BFS就好了。

  • 我们甚至不需要知道级别,而是在遇到最终节点后我们可以得到最终的数字。

这可以编译成一个非常简单的算法,主要只是BFS。

 - Mark nodes as visited as usual with BFS.
 - Instead of adding just nodes to the queue in the DFS add nodes plus number of incoming paths.
 - If a node that has been visited should be added ignore it.
 - If you find a node again, which is currently in the queue, do not add it again, instead add the counts together.
 - Propagate the counts on the queue when adding new nodes.
 - when you encounter the final, the number that is stored with it, is the number of possible paths.

答案 1 :(得分:9)

您的算法会在

这样的图表上中断
  *   *   *   1
 / \ / \ / \ / \
v   *   *   *   w
 \ / \ / \ / \ /
  *   *   *   2

所有边缘从左向右指向。它计算两条路径,一条通过1,另一条通过2,但12都可以通过八条不同的最短路径从v到达,一共十六个。

答案 2 :(得分:4)

正如qrqrq所示,您的算法在某些图表上失败,但BFS的想法很好。相反,维护一个大小为z的数组|V|,您将其初始化为零;在[{1}}中保留距离小于i的已发现顶点level的最短路径数。同时维护一个大小为z[i]的数组d,使得|V|d[i]到顶点v的距离(如果该距离小于i} 。将level初始化为0,将level初始化为0,将d[v]初始化为1(从z[v]v有一条长度为0的路径,并设置vd以及-1z的所有其他条目。

现在,只要您在BFS中遇到0i的边缘,就会:

  • 如果j,则设置d[j] = -1d[j] := level
  • 如果z[j] := z[i],则设置d[j] = level
  • 否则,什么都不做。

原因是,从z[j] := z[j] + z[i]v的每条最短路径,都有一条从iv的最短路径。这将给出线性时间内从j到每个顶点的最短路径数。现在再次执行相同操作,但从v开始。

答案 3 :(得分:2)

这个算法对我来说是正确的。

正如您所知,BFS是一个线性时间(O(N))搜索,因为完成它所需的时间T最差的是T = C + a * N,其中N是节点数,Ca是任何固定常数。

在您的情况下,执行两次搜索 - 首先从vw,然后从w再到v - 是(最差){{1} }或2T,如果您定义新的2C + 2a * N和新的O(N),也会满足线性时间要求C' = 2C,因为a' = 2a和{ {1}}也是固定常量。

答案 4 :(得分:2)

int edgeCb( graphPT g, int x, int y )
{
    if ( dist[ y ] > dist[ x ] + 1 ) {
        dist[ y ] = dist[ x ] + 1; // New way
        ways[ y ] = ways[ x ]; // As many ways as it's parent can be reached
    } else if ( dist[ y ] == dist[ x ] + 1 ) {
        ways[ y ] += ways[ x ]; // Another way
    } else {
        // We already found a way and that is the best
        assert( dist[ y ] < g->nv );
    }
    return 1;
}

上面的代码为我提供了本文中提到的所有类型图表的正确结果。基本上它是BFS遍历的边缘回调。

dist [start] = 0; 方式[开始] = 1;

休息所有顶点 dist [x] = numberOfVertices; //这超出了最大可能的失误

BFS(g,start);

如果[end]方式不为零,则表示方式的数量,dist [end]表示最短距离。

包含方式[结束] == 0表示无法从开始到达结束。

如果有任何循环漏洞,请告诉我。

答案 5 :(得分:2)

更改BFS最简单的解决方案:

count(v)= 0,count(s)= 1.对于v的每个邻居u,如果(d(v)+ 1 == d(u)),则count(u)+ = count(v )。现在重置所有内容并从末端顶点执行相同的操作。

答案 6 :(得分:0)

我可以这样做吗

  1. 我使用BFS遍历,直到到达目的地顶点并保持水平
  2. 一旦我到达目的地级别,我使用级别表如下
  3. 从关卡表开始,我开始遍历计算父路径到路径中顶点的数量(第一次它将是目标顶点)。
       在每一步,我将在该特定级别找到的不同父级的数量乘以我可以到达目标顶点的最短路径。
      我向上移动,只考虑落入我路径的节点,并将每个级别的不同父级的数量相乘,直到达到0级。

    这有用吗?

答案 7 :(得分:0)

只需检查此处给出的正确解释即可:

https://www.geeksforgeeks.org/number-shortest-paths-unweighted-directed-graph/

简而言之,我们可以修改任何最短路径算法, 当更新步骤到来时,将增加一个计数器 当前路径建议具有以下条件时先前发现的最短路径 在那一刻之前找到的最短路径的长度相同。

在特定情况下,当它是未加权或恒定的图形时 权重,最简单的方法是修改BFS。