递归函数的复杂性,用于计算图中的路径

时间:2015-02-19 21:10:24

标签: c++ algorithm recursion graph time-complexity

我找到了一个有向图的函数,对于它中的顶点'u'和'v',它计算从'u'到'v'的所有可能的步行,其中在步行中具有正好k个边缘。 代码和算法来自here。所以,

// C++ program to count walks from u to v with exactly k edges
#include <iostream>
using namespace std;

// Number of vertices in the graph
#define V 4

// A naive recursive function to count walks from u to v with k edges
int countwalks(int graph[][V], int u, int v, int k)
{
   // Base cases
   if (k == 0 && u == v)      return 1;
   if (k == 1 && graph[u][v]) return 1;
   if (k <= 0)                return 0;

   // Initialize result
   int count = 0;

   // Go to all adjacents of u and recur
   for (int i = 0; i < V; i++)
       if (graph[u][i])  // Check if is adjacent of u
           count += countwalks(graph, i, v, k-1);

   return count;
}

我试图找到并证明这种算法的复杂性。根据帖子:

  

“上述函数的最坏情况时间复杂度为O(V ^ k),其中V   是给定图形中的顶点数。我们可以简单地分析   绘制递归树的时间复杂度。最坏的情况发生在   完整的图表。在最坏的情况下,递归树的每个内部节点   肯定会有n个孩子。“

但是,我无法找到导致我可以分析的树的递归,以证明此算法是O(V^k)。另外,我认为最好的情况是Theta(1)。真的吗?平均情况怎么样?

2 个答案:

答案 0 :(得分:1)

对于完整的图表,每个节点都连接到其他节点,因此for循环将进行|V|递归调用。这将在每次递归调用时发生,直到k变为1,因此总共O(|V|^k)次递归调用。

你可以这样表达:

T(V, k) = |V|*T(V, k - 1)
        = |V|*|V|*T(V, k - 2)
        = |V|^2*|V|*T(V, k - 3)
        = ...

始终为T(V, _),因为可以多次访问节点。

最好的情况确实是O(1),当前三个条件中的一个条件在第一次通话期间触发时。{/ p>

我不确定的平均情况,但我认为它应该仍然很糟糕。考虑链接列表图和巨大的k:您将多次移动相同的边缘以使k为0或1.随着您添加更多路径,这会逐渐变得更糟。

答案 1 :(得分:0)

通用的“平均情况”分析在这样的问题中有点不适应,因为您可以选择如何定义“随机”图形。一种方式是说每个可能的边缘以0 <= p <= 1的概率p出现,然后尝试用p来分析平均情况运行时间。但是还有其他方法来定义随机图。平均案例分析通常很难。但是,如果你用“平均”来定义你的意思(即它是什么意思是随机图)那么有人可能会对它进行刺激。