【问题标题】:Prim's algorithm on graph with weights of only 1 and 2 on each edge using two listsPrim 算法在图上使用两个列表,每条边的权重仅为 1 和 2
【发布时间】:2025-12-11 21:55:01
【问题描述】:

给定一个加权的、连通的、简单的无向图 G,每条边的权重只有 1 和 2

我想这样实现Prim's algorithm

权重是 1 或 2,所以我可以简单地将边存储在 2 个单独的列表中,一个用于权重为 1 的边,第二个用于权重为 2 的边。

要找到权重最低的边,我只需从第一个列表中取一个,除非它是空的,在这种情况下,我从第二个列表中取一个边。

从列表中访问和删除元素是 O(1),因此 Prim 的算法将在 O(V+E) 中运行。

package il.ac.oranim.alg2016;

import edu.princeton.cs.algs4.*; 

public class MST12 {    
    private int weight; // weight of the tree
    private Edge[] mstEdges; // use this to store the edges of your Minimum Spanning Tree

    public MST12(EdgeWeightedGraph G, int s)  throws IndexOutOfBoundsException, DisconnectedGraphException, WrongWeightException {
        // check that the starting vertex is in the range 0,1,...,G.V()
        if (s < 0 || s >= G.V()) {
            throw new IndexOutOfBoundsException();
        }
        // check that the input graph is connected otherwise there is no (minimum) spanning tree
        if (isConnected(G) == false) {
            throw new DisconnectedGraphException();
        }
        // check that all the weights are 1 or 2
        for (Edge e : G.edges()) {
            if (e.weight() != 1 && e.weight() != 2) {
                throw new WrongWeightException();
            }
        }

        this.weight = 0; // make sure you update this value

        // replace -->
        // your code goes here
        // <-- replace
    }

    // returns the weight of the tree
    public int weight() {
        return this.weight;
    }

    // checks whether a graph is connected
    private static boolean isConnected(EdgeWeightedGraph G) {
        // create a graph of class Graph with the same edges (weights)
        Graph g = new Graph(G.V());
        for (Edge e : G.edges()) {
            int v = e.either();
            g.addEdge(v, e.other(v));
        }
        // compute the connected components of the graph
        CC cc = new CC(g);

        // return true iff there is only one connected component
        return cc.count() == 1;
    }

    /**
     * Returns the edges in a minimum spanning tree as
     *    an iterable of edges
     */
    public Iterable<Edge> edges() {
        Queue<Edge> edges = new Queue<Edge>();
        for (int i = 0; i < this.mstEdges.length; i++) {
            Edge e = this.mstEdges[i];
            int v = e.either();
            edges.enqueue(new Edge(v, e.other(v), e.weight()));
        }
        return edges;
    }

    /**
     * test the computing of an MST of a graph with weights 1 and 2 only
     * the first argument is the name of the file that contains the graph (graph1.txt, graph2.txt, or graph3.txt)
     * you can define this argument in Run.. --> (x)=Arguments
     */
    public static void main(String[] args) {
        In in = new In(args[0]);
        EdgeWeightedGraph G = new EdgeWeightedGraph(in);

        PrimMST primMST = new PrimMST(G);       
        MST12 mst12 = null;
        try {
            mst12 = new MST12(G,0);
        }
        catch (DisconnectedGraphException e) {
            System.err.println("the input graph is not connected and hence has no (minimum) spanning tree");
        }
        catch (WrongWeightException e) {
            System.err.println("not all weights in the input graph are 1 or 2");            
        }

        System.out.println("Prim's MST weight = " + primMST.weight());
        System.out.println("My MST's weight = " + mst12.weight());
    }
}

我卡在//replace--&gt;//your code goes here//replace&lt;--的部分

两个需要的类:

package il.ac.oranim.alg2016;

public class DisconnectedGraphException extends Exception {
    public DisconnectedGraphException() {}
}

  package il.ac.oranim.alg2016;

  public class WrongWeightException extends Exception {
      public WrongWeightException() {}
  }

我也可以使用所有这些http://algs4.cs.princeton.edu/code/

有人可以帮我解决这部分吗//replace--&gt;//your code goes here//replace&lt;--

我尝试将This 代码复制到//&lt;--relpace,//replace--&gt; 部分,然后将其从使用堆更改为两个列表。

Pseudocode of Prim's algorithm

换句话说,我需要代码:

【问题讨论】:

  • 您的问题到底是什么?您是否尝试使用帖子中描述的两个列表来实施解决方案?如果是,出了什么问题?

标签: java eclipse algorithm graph minimum-spanning-tree


【解决方案1】:

首先,使用运行在 O(|E|log(|V|)) 中的优先级队列实现普通 Prim 算法。自己做而不是复制书的代码。如果你不能自己实现 Prim 的算法,你就无法理解如何扩展到算法。

然后,作为 D.W. https://cs.stackexchange.com/questions/66498/prims-algorithm-on-graph-with-weights-of-only-1-and-2-on-each-edge 建议您可以将 ExtractMin、Remove 和 Insert 函数更改为 O(1)。

这个想法是您可以保留权重 1 和 2 的边列表。如果边权重 1 的列表不为空,那么您可以通过在 O(1 ) 时间。如果边权重 1 的列表为空,则可以通过在 O(1) 时间内弹出权重 2 的列表来获得下一个最佳边。

与普通 Prim 算法的唯一变化是您需要这样的数据结构:

private class SpecialPQ {
    ArrayList<NodeWeightPair> _queueWeight1 = new ArrayList<NodeWeightPair>();
    ArrayList<NodeWeightPair> _queueWeight2 = new ArrayList<NodeWeightPair>();

    public void insert(NodeWeightPair e) {
        if (e._weight == 1) {
            _queueWeight1.add(e);
        }
        else {
            _queueWeight2.add(e);
        }
    }

    public void remove() {
        if (_queueWeight1.size() == 0) {
            _queueWeight2.remove(_queueWeight2.size()-1);
        }
        else {
            _queueWeight1.remove(_queueWeight1.size()-1);
        }
    }

    public NodeWeightPair extractMin() {
        if (_queueWeight1.size() > 0) {
            return _queueWeight1.get(_queueWeight1.size()-1);
        }
        else {
            return _queueWeight2.get(_queueWeight2.size()-1);
        }
    }

    public boolean empty() {
        return _queueWeight1.size() == 0 && _queueWeight2.size() == 0;
    }
};

Normal Prim 的算法使用二叉堆优先级队列来获得 O(|E|log(|V|))。你只需要用这个更快的SpecialPQ 替换二进制堆优先级队列。

所以书的代码有这一行:

private IndexMinPQ<Double> pq;

你只需要把它改成

private SpecialPQ pq;

然后编译剩下的代码。不要从字面上复制和粘贴我的代码SpecialPQ。您需要很长时间才能使其与本书的代码兼容。相反,我认为您应该编写自己的 SpecialPQ,它可以与您自己的 Prim 算法实现一起使用。

我在本地有一个工作示例 - 我自己的实现,因此它与本书的代码不兼容。如果您发布实现此功能的尝试,我会分享我的。

编辑:

节点权重对

private class NodeWeightPair {

    private int _parent;
    private int _node;
    private int _weight;
    public NodeWeightPair(int parent, int node, int weight) {
        _node = node;
        _weight = weight;
        _parent = parent;
    }
}

【讨论】:

  • 你能告诉我ArrayListNodeWeightPair的类吗?
  • 我添加了NodeWeightPairArrayListjava.util.ArrayList
  • 您的 SpecialPQ 更像是优先级堆栈...为什么您更喜欢 ArrayList 而不是 LinkedList?
  • 无论我使用ArrayList 还是LinkedListextractMin 仍然给你下一个最小的元素。运行时仍然相同 - O(1) 从 ArrayList 的末尾弹出,从 Queue 的前面轮询 O(1),表示为 LinkedList。对于这个问题,内存似乎不像运行时那么大。我只选择了ArrayList,因为在一些额外的内存成本下,内存被分配在一个连续的块中,与LinkedList 相比,这可能导致更多的缓存命中和更低的绝对(非渐近)运行时间。
  • 为什么更喜欢 ArrayList 而不是 Stack 对象?
【解决方案2】:
  package il.ac.oranim.alg2016;

 import edu.princeton.cs.algs4.*; 

 public class MST_12
{   
private int weight; // weight of the tree
private Edge[] mstEdges; // MST edges

private boolean[] marked;// MST vertices
private Queue<Edge> queueWeight1; 
private Queue<Edge> queueWeight2; 

   public MST_12(EdgeWeightedGraph G, int s)  throws      IndexOutOfBoundsException, DisconnectedGraphException, WrongWeightException 
{
    // check that the starting vertex is in the range 0,1,...,G.V()
    if (s < 0 || s >= G.V()) {
        throw new IndexOutOfBoundsException();
    }
    // check that the input graph is connected otherwise there is no (minimum) spanning tree
    if (isConnected(G) == false) {
        throw new DisconnectedGraphException();
    }
    // check that all the weights are 1 or 2
    for (Edge e : G.edges()) {
        if (e.weight() != 1 && e.weight() != 2) {
            throw new WrongWeightException();
        }
    }

    this.weight = 0; // make sure you update this value

    // replace -->

    queueWeight1 = new Queue<Edge>();
    queueWeight2 = new Queue<Edge>();
    mstEdges=new Edge[G.V()];
    marked=new boolean[G.V()];  

     for (int v = 0; v < G.V(); v++)      // run from each vertex to find
            if (!marked[v]) KPrim(G,v);// minimum spanning forest
}

  private void KPrim ( EdgeWeightedGraph G, int s)
    {
         visit(G,s);
         while (!queueWeight1.isEmpty()||!queueWeight2.isEmpty()){   
              Edge e=null;
              if (!queueWeight1.isEmpty())
                 { e=queueWeight1.dequeue();}
              else if (!queueWeight2.isEmpty()){e=queueWeight2.dequeue();}
              int v=e.either(), w=e.other(v);
              assert marked [v]||marked [w];
              if(marked[v]&&marked[w]) continue;
              mstEdges[s]=e;
              weight+=e.weight();
              if(!marked[v]) visit(G,v);// v becomes part of tree
              if(!marked[w]) visit(G,w);// w becomes part of a tree
         }          
    }

//add all edges e incident to v onto queue if the other endpoint has not yet been scanned
    private void visit (EdgeWeightedGraph G, int v)
    {
    marked[v]=true;// add v to T
    for (Edge e : G.adj(v))// for each edge e=v-w, add to queueWeight if w not already in T  
    { 
       if(!marked[e.other(v)])  {       
            if (e.weight()==1.0) {queueWeight1.enqueue(e);mstEdges[v]=e;}//add the smallest edge weight to the mst weight
            else {queueWeight2.enqueue(e);mstEdges[v]=e;}}}

    }

    // <-- replace


// returns the weight of the tree
public int weight() {
    return this.weight;
}

// checks whether a graph is connected
private static boolean isConnected(EdgeWeightedGraph G) {
    // create a graph of class Graph with the same edges (weights)
    Graph g = new Graph(G.V());
    for (Edge e : G.edges()) {
        int v = e.either();
        g.addEdge(v, e.other(v));
    }
    // compute the connected components of the graph
    CC cc = new CC(g);

    // return true iff there is only one connected component
    return cc.count() == 1;
}

/**
 * Returns the edges in a minimum spanning tree as
 *    an iterable of edges
 */
public Iterable<Edge> edges() {
    Queue<Edge> edges = new Queue<Edge>();
    for (int i = 0; i < this.mstEdges.length; i++) {
        Edge e = this.mstEdges[i];
        int v = e.either();
        edges.enqueue(new Edge(v, e.other(v), e.weight()));
    }
    return edges;
}

/**
 * test the computing of an MST of a graph with weights 1 and 2 only
 * the first argument is the name of the file that contains the graph (graph1.txt, graph2.txt, or graph3.txt)
 * you can define this argument in Run.. --> (x)=Arguments
 */
public static void main(String[] args) {
    In in = new In(args[0]);
    EdgeWeightedGraph G = new EdgeWeightedGraph(in);

    PrimMST primMST = new PrimMST(G);       
    MST_12 mst12 = null;
    try {
        mst12 = new MST_12(G,0);
    }
    catch (DisconnectedGraphException e) {
        System.err.println("the input graph is not connected and hence has no (minimum) spanning tree");
    }
    catch (WrongWeightException e) {
        System.err.println("not all weights in the input graph are 1 or 2");            
    }

    System.out.println("Prim's MST weight = " + primMST.weight());
    System.out.println("My MST's weight = " + mst12.weight());
}
}

【讨论】: