以下是练习:
令v和w为有向图G =(V,E)中的两个顶点。设计线性时间算法以找到v和w之间的不同最短路径(不一定是顶点不相交)的数量。注意:G中的边是未加权的
对于这个消费税,我总结如下:
从以上几点来看,我有以下想法:
count
global level
信息global level
增加1,然后BFS达到新的水平shortest level
信息以获取最短路径global level
分配给shortest level
和count++
; global level
等于shortest level
,我每次见到w时都会增加count
。global level
变得大于shortest level
,我会终止旅行,因为我正在寻找最短路径而不是路径。我的算法是否正确?如果我做v然后w到v,那还是被认为是线性时间吗?
答案 0 :(得分:20)
以下是对此的一些看法。
证明:如果有多条路径通过相同的顶点进入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
,但1
和2
都可以通过八条不同的最短路径从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的路径,并设置v
到d
以及-1
到z
的所有其他条目。
现在,只要您在BFS中遇到0
到i
的边缘,就会:
j
,则设置d[j] = -1
和d[j] := level
。z[j] := z[i]
,则设置d[j] = level
。原因是,从z[j] := z[j] + z[i]
到v
的每条最短路径,都有一条从i
到v
的最短路径。这将给出线性时间内从j
到每个顶点的最短路径数。现在再次执行相同操作,但从v
开始。
答案 3 :(得分:2)
这个算法对我来说是正确的。
正如您所知,BFS是一个线性时间(O(N)
)搜索,因为完成它所需的时间T
最差的是T = C + a * N
,其中N
是节点数,C
,a
是任何固定常数。
在您的情况下,执行两次搜索 - 首先从v
到w
,然后从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)
我可以这样做吗
从关卡表开始,我开始遍历计算父路径到路径中顶点的数量(第一次它将是目标顶点)。
在每一步,我将在该特定级别找到的不同父级的数量乘以我可以到达目标顶点的最短路径。
我向上移动,只考虑落入我路径的节点,并将每个级别的不同父级的数量相乘,直到达到0级。
这有用吗?
答案 7 :(得分:0)
只需检查此处给出的正确解释即可:
https://www.geeksforgeeks.org/number-shortest-paths-unweighted-directed-graph/
简而言之,我们可以修改任何最短路径算法, 当更新步骤到来时,将增加一个计数器 当前路径建议具有以下条件时先前发现的最短路径 在那一刻之前找到的最短路径的长度相同。
在特定情况下,当它是未加权或恒定的图形时 权重,最简单的方法是修改BFS。