最小生成树的运行时间? (普里姆法)

发布于 2024-08-11 17:39:01 字数 1444 浏览 8 评论 0原文

我编写了一个使用 Prim 方法求解 MST 的代码。我读到这种实现(使用优先级队列)应该有 O(E + VlogV) = O(VlogV),其中 E 是边数,V 是边数,但是当我查看我的代码时,它根本不看起来如果有人能为我解决这个问题,我将不胜感激。

对我来说,运行时间似乎是这样的:

while 循环需要 O(E) 次(直到我们遍历所有边缘) 在该循环中,我们从 Q 中提取一个元素,这需要 O(logE) 时间。 第二个内部循环需要 O(V) 时间(尽管我们不会每次都运行这个循环 很明显,它将运行 V 次,因为我们必须添加所有顶点)

我的结论是运行时间为:O( E(logE+V) ) = O( E*V )。

这是我的代码:

#define p_int pair < int, int >

int N, M; //N - nmb of vertices, M - nmb of edges
int graph[100][100] = { 0 }; //adj. matrix
bool in_tree[100] = { false }; //if a node if in the mst
priority_queue< p_int, vector < p_int >, greater < p_int > > Q; 
/*
keeps track of what is the smallest edge connecting a node in the mst tree and
a node outside the tree. First part of pair is the weight of the edge and the 
second is the node. We dont remember the parent node beaceuse we dont need it :-)
*/

int mst_prim()
{
 Q.push( make_pair( 0, 0 ) );

 int nconnected = 0;
 int mst_cost = 0;
 while( nconnected < N )
 {
      p_int node = Q.top(); Q.pop();

      if( in_tree[ node.second ] == false )
      {
           mst_cost += node.first;
           in_tree[ node.second ] = true;

           for( int i = 0; i < N; ++i )
                if( graph[ node.second ][i] > 0 && in_tree[i]== false )
                     Q.push( make_pair( graph[ node.second ][i], i ) );

           nconnected++;
      }
 }

 return mst_cost;
}

I have written a code that solves MST using Prim method. I read that this kind of implementation(using priority queue) should have O(E + VlogV) = O(VlogV) where E is the number of edges and V number of Edges but when I look at my code it simply doesn't look that way.I would appreciate it if someone could clear this up for me.

To me it seems the running time is this:

The while loop takes O(E) times(until we go through all the edges)
Inside that loop we extract an element from the Q which takes O(logE) time.
And the second inner loop takes O(V) time(although we dont run this loop everytime
it is clear that it will be ran V times since we have to add all the vertices )

My conclusion would be that the running time is: O( E(logE+V) ) = O( E*V ).

This is my code:

#define p_int pair < int, int >

int N, M; //N - nmb of vertices, M - nmb of edges
int graph[100][100] = { 0 }; //adj. matrix
bool in_tree[100] = { false }; //if a node if in the mst
priority_queue< p_int, vector < p_int >, greater < p_int > > Q; 
/*
keeps track of what is the smallest edge connecting a node in the mst tree and
a node outside the tree. First part of pair is the weight of the edge and the 
second is the node. We dont remember the parent node beaceuse we dont need it :-)
*/

int mst_prim()
{
 Q.push( make_pair( 0, 0 ) );

 int nconnected = 0;
 int mst_cost = 0;
 while( nconnected < N )
 {
      p_int node = Q.top(); Q.pop();

      if( in_tree[ node.second ] == false )
      {
           mst_cost += node.first;
           in_tree[ node.second ] = true;

           for( int i = 0; i < N; ++i )
                if( graph[ node.second ][i] > 0 && in_tree[i]== false )
                     Q.push( make_pair( graph[ node.second ][i], i ) );

           nconnected++;
      }
 }

 return mst_cost;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

零崎曲识 2024-08-18 17:39:01

您可以使用邻接表来加速您的解决方案(但不适用于密集图),但即便如此,如果没有斐波那契堆,您也不会得到 O(V log V) 。

也许 Kruskal 算法 会让您更容易理解。它没有优先级队列,您只需对边数组进行一次排序。基本上是这样的:

  • 将所有边插入数组并按权重对它们进行
  • 排序迭代排序后的边,对于连接节点 i 和 j 的每条边,检查 i 和 j 是否连接。如果是,则跳过该边,否则将该边添加到 MST 中。

唯一的问题是能够快速判断两个节点是否已连接。为此,您使用并查数据结构,如下所示:

int T[MAX_#_OF_NODES]

int getParent(int a)
{
  if (T[a]==-1)return a;
  return T[a]=getParent(T[a]);
}
void Unite(int a,int b)
{
  if (rand()&1)
     T[a]=b;
  else
     T[b]=a;
}

一开始,只需将 T 初始化为全 -1,然后每次您想查明节点 A 和 B 是否连接时,只需比较它们的父节点 -如果它们相同,则它们是连接的(就像这样 getParent(A)==getParent(B))。将边插入 MST 时,请确保使用 Unite(getParent(A),getParent(B)) 更新并查。

分析很简单,您对边进行排序并使用需要 O(1) 的 UF 进行迭代。所以它是 O(E logE + E ) 等于 O(E log E)。

就是这样;-)

You can use adjacency lists to speed your solution up (but not for dense graphs), but even then, you are not going to get O(V log V) without a Fibonacci heap..

Maybe the Kruskal algorithm would be simpler for you to understand. It features no priority queue, you only have to sort an array of edges once. It goes like this basically:

  • Insert all edges into an array and sort them by weight
  • Iterate over the sorted edges, and for each edge connecting nodes i and j, check if i and j are connected. If they are, skip the edge, else add the edge into the MST.

The only catch is to be quickly able to say if two nodes are connected. For this you use the Union-Find data structure, which goes like this:

int T[MAX_#_OF_NODES]

int getParent(int a)
{
  if (T[a]==-1)return a;
  return T[a]=getParent(T[a]);
}
void Unite(int a,int b)
{
  if (rand()&1)
     T[a]=b;
  else
     T[b]=a;
}

In the beginning, just initialize T to all -1, and then every time you want to find out if nodes A and B are connected, just compare their parents - if they are the same, they are connected (like this getParent(A)==getParent(B)). When you are inserting the edge to MST, make sure to update the Union-Find with Unite(getParent(A),getParent(B)).

The analysis is simple, you sort the edges and iterate over using the UF that takes O(1). So it is O(E logE + E ) which equals O(E log E).

That is it ;-)

一念一轮回 2024-08-18 17:39:01

我之前不需要处理该算法,但是您所实现的与

  1. 但所有顶点都进入队列。 O(V)
  2. 当队列不为空时... O(V)
    1. 从队列中取出权重最小的边。 O(log(V))
    2. 更新相邻顶点的权重。 O(E / V),这是相邻顶点的平均数。
    3. 重新建立队列结构。 O(log(V))

        O(V) + O(V) * (O(log(V)) + O(V/E))
      = O(V) + O(V) * O(log(V)) + O(V) * O(E / V)
      = O(V) + O(V * log(V)) + O(E)
      = O(V * log(V)) + O(E)

正是人们所期望的。

I did not have to deal with the algorithm before, but what you have implemented does not match the algorithm as explained on Wikipedia. The algorithm there works as follows.

  1. But all vertices into the queue. O(V)
  2. While the queue is not empty... O(V)
    1. Take the edge with the minimum weight from the queue. O(log(V))
    2. Update the weights of adjacent vertices. O(E / V), this is the average number of adjacent vertices.
    3. Reestablish the queue structure. O(log(V))

This gives

        O(V) + O(V) * (O(log(V)) + O(V/E))
      = O(V) + O(V) * O(log(V)) + O(V) * O(E / V)
      = O(V) + O(V * log(V)) + O(E)
      = O(V * log(V)) + O(E)

exactly what one expects.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文