Algorithm 计算有向图上非循环路径数的快速算法
简而言之,我需要一个快速算法来计算一个简单有向图中有多少条非循环路径 所谓简单图,我指的是没有自循环或多条边的图。 路径可以从任何节点开始,并且必须在没有传出边的节点上结束。如果路径中没有两次出现边,则该路径是非循环的 我的图(经验数据集)只有20-160个节点,但是,其中一些节点中有许多循环,因此将有大量的路径,而我的简单方法对于我的一些图来说还不够快 我目前正在做的是使用递归函数沿所有可能的边“递减”,同时跟踪我已经访问过的节点(并避开它们)。到目前为止,我所用的最快的解决方案是用C++编写的,并且在递归函数中使用STD::BITSSET参数来跟踪哪些节点已经被访问过(访问节点用位1标记)。该程序在样本数据集上运行1-2分钟(取决于计算机速度)。对于其他数据集,运行需要一天以上的时间,或者显然要长得多 示例数据集: (每条线是一对边) 示例数据集的解决方案(第一个数字是我从中开始的节点,第二个数字是从该节点开始的路径计数,最后一个数字是总路径计数): 请让我知道,如果你有一个更复杂的算法的想法。我还对近似解感兴趣(用蒙特卡罗方法估计路径数)。最后,我还要测量平均路径长度 编辑:也以相同的标题发布在MathOverflow上,因为它可能与MathOverflow更相关。希望这不违反规定。无法链接,因为站点不允许超过2个链接…这似乎是“p-完成”。(参考)。链接有一个近似值Algorithm 计算有向图上非循环路径数的快速算法,algorithm,optimization,graph,complexity-theory,directed-graph,Algorithm,Optimization,Graph,Complexity Theory,Directed Graph,简而言之,我需要一个快速算法来计算一个简单有向图中有多少条非循环路径 所谓简单图,我指的是没有自循环或多条边的图。 路径可以从任何节点开始,并且必须在没有传出边的节点上结束。如果路径中没有两次出现边,则该路径是非循环的 我的图(经验数据集)只有20-160个节点,但是,其中一些节点中有许多循环,因此将有大量的路径,而我的简单方法对于我的一些图来说还不够快 我目前正在做的是使用递归函数沿所有可能的边“递减”,同时跟踪我已经访问过的节点(并避开它们)。到目前为止,我所用的最快的解决方案是用C++编写
如果您可以放宽简单路径的要求,那么您也可以使用经过修改的Floyd Warshall版本或图形求幂来有效地计算路径数。如Spining_plate所述,这个问题是完全的,所以开始寻找你的答案:)。我真的很喜欢这个问题的#P-完备性证明,所以我想分享一下会很好: 设N是图中的路径数(从s开始),p_k是长度为k的路径数。我们有:
N = p_1 + p_2 + ... + p_n
现在通过将每条边更改为一对平行边来构建第二个图。对于长度为k的每条路径,现在将有k^2条路径,因此:
N_2 = p_1*2 + p_2*4 + ... + p_n*(2^n)
重复这个过程,但用i边代替2,向上n,会给我们一个线性系统(带范德蒙矩阵),让我们找到p_1,…,p_n
N_i = p_1*i + p_2*(i^2) + ...
因此,在图中查找路径数与查找特定长度的路径数一样困难。特别是,p#n是哈密顿路径的数目(从s开始),这是一个真正的p-完全问题
我还没有做过数学计算,我猜类似的过程应该能够证明仅仅计算平均长度也是很困难的
注意:大多数情况下,讨论此问题时,路径从一条边开始,并在任何位置停止。这与你的问题正好相反,但你应该把所有的边都颠倒过来,使它们相等。问题陈述的重要性 目前尚不清楚统计的是什么
#include <iostream>
#include <list>
class DirectedGraph {
private:
int miNodes;
std::list<int> * mnpEdges;
bool * mpVisitedFlags;
private:
void initAlreadyVisited() {
for (int i = 0; i < miNodes; ++ i)
mpVisitedFlags[i] = false;
}
void recurse(int iCurrent, int iDestination,
int path[], int index,
std::list<std::list<int> *> * pnai) {
mpVisitedFlags[iCurrent] = true;
path[index ++] = iCurrent;
if (iCurrent == iDestination) {
auto pni = new std::list<int>;
for (int i = 0; i < index; ++ i)
pni->push_back(path[i]);
pnai->push_back(pni);
} else {
auto it = mnpEdges[iCurrent].begin();
auto itBeyond = mnpEdges[iCurrent].end();
while (it != itBeyond) {
if (! mpVisitedFlags[* it])
recurse(* it, iDestination,
path, index, pnai);
++ it;
}
}
-- index;
mpVisitedFlags[iCurrent] = false;
}
public:
DirectedGraph(int iNodes) {
miNodes = iNodes;
mnpEdges = new std::list<int>[iNodes];
mpVisitedFlags = new bool[iNodes];
}
~DirectedGraph() {
delete mpVisitedFlags;
}
void addEdge(int u, int v) {
mnpEdges[u].push_back(v);
}
std::list<std::list<int> *> * findPaths(int iStart,
int iDestination) {
initAlreadyVisited();
auto path = new int[miNodes];
auto pnpi = new std::list<std::list<int> *>();
recurse(iStart, iDestination, path, 0, pnpi);
delete path;
return pnpi;
}
};
int main() {
DirectedGraph dg(5);
dg.addEdge(0, 1);
dg.addEdge(0, 2);
dg.addEdge(0, 3);
dg.addEdge(1, 3);
dg.addEdge(1, 4);
dg.addEdge(2, 0);
dg.addEdge(2, 1);
dg.addEdge(4, 1);
dg.addEdge(4, 3);
int startingNode = 0;
int destinationNode = 1;
auto pnai = dg.findPaths(startingNode, destinationNode);
std::cout
<< "Unique paths from "
<< startingNode
<< " to "
<< destinationNode
<< std::endl
<< std::endl;
bool bFirst;
std::list<int> * pi;
auto it = pnai->begin();
auto itBeyond = pnai->end();
std::list<int>::iterator itInner;
std::list<int>::iterator itInnerBeyond;
while (it != itBeyond) {
bFirst = true;
pi = * it ++;
itInner = pi->begin();
itInnerBeyond = pi->end();
while (itInner != itInnerBeyond) {
if (bFirst)
bFirst = false;
else
std::cout << ' ';
std::cout << (* itInner ++);
}
std::cout << std::endl;
delete pi;
}
delete pnai;
return 0;
}
#包括
#包括
类定向图{
私人:
内米诺德斯;
标准::列表*mnpEdges;
bool*mpVisitedFlags;
私人:
void initAlreadyVisited(){
对于(int i=0;i