2016-11-30 75 views
5

względu ważonej, związany prosty nieukierunkowane wykres kz wag tylko 1 i 2 na każdej krawędziPrim na wykresie z mas tylko 1 i 2, każda krawędź stosując dwa wykazy

I zaimplementować Prim's algorithm tę sposób:

obciążniki są 1 lub 2, aby można było łatwo przechowywać krawędzie 2 oddzielnych wykazów, jeden do krawędzi o masie 1, a drugi do krawędzi o masie 2.

Aby znaleźć krawędzią przy najniższej wadze po prostu biorę jedną z pierwszej listy, chyba że jest pusta, w takim przypadku biorę przewagę z drugiej listy.

Uzyskiwanie dostępu i usuwanie elementu z listy to O (1), więc algorytm Prim będzie działał w 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()); 
    } 
} 

siedzę w ramach //replace-->//your code goes here//replace<--

dwóch klas, które potrzebne:

package il.ac.oranim.alg2016; 

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

i

package il.ac.oranim.alg2016; 

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

także mam prawo do korzystania to wszystko http://algs4.cs.princeton.edu/code/

może ktoś mi pomóc proszę z tą częścią //replace-->//your code goes here//replace<--

Próbowałem skopiować kod This do //<--relpace,//replace--> części, a następnie do nóg to, aby go zmienić z użyciem sterty dwóch list.

Pseudocode of Prim's algorithm

Innymi słowy muszę kod to:

enter image description here

+0

Co dokładnie masz problem? Czy próbowałeś zaimplementować rozwiązanie z dwiema listami opisanymi w twoim poście? Jeśli tak, co poszło nie tak? – kraskevich

Odpowiedz

0
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()); 
} 
} 
2

pierwsze wdrożenie algorytmu normalnego Prim jest z kolejki priorytetowej, który działa w czasie O (| E | log (| V |)). Zrób to sam zamiast kopiować kod książki. Jeśli nie możesz sam wdrożyć algorytmu Prim, nie będziesz w stanie zrozumieć, jak rozszerzyć ten algorytm.

Następnie, jako D.W. sugerowane przy https://cs.stackexchange.com/questions/66498/prims-algorithm-on-graph-with-weights-of-only-1-and-2-on-each-edge możesz zmienić funkcje ExtractMin, Remove i Insert na O (1).

Pomysł polega na tym, że można zachować listę krawędzi o wadze 1 i 2. Jeśli lista grubości krawędzi 1 nie jest pusta, można uzyskać następną najlepszą krawędź do użycia, wyskakując z listy w O (1 raz. Jeśli lista dla grubości krawędzi 1 jest pusta, wówczas kolejne najlepsze krawędzie można uzyskać, wyskakując z listy o wadze 2 w czasie O (1).

Jedyna zmiana algorytmu normalnego Prim jest to, że trzeba to struktura danych tak:

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; 
    } 
}; 

Algorytm Normalny Prim wykorzystuje binarną priorytet sterty kolejkę dostać O (| E | log (| V |))). Musisz tylko zastąpić binarną kolejkę priorytetową sterty tym szybszym SpecialPQ.

Więc kod tej książki ma ten wiersz:

private IndexMinPQ<Double> pq; 

Będziesz wystarczy zmienić na

private SpecialPQ pq; 

i dostać reszta kodu do kompilacji. Nie dosłownie kopiuj i wklej mój kod na SpecialPQ. Zajmie ci to dużo czasu, aby było zgodne z kodem książki. Zamiast tego, myślę, że powinieneś napisać własną SpecialPQ, która będzie działać z twoją implementacją algorytmu Prim.

Mam działający przykład lokalnie - moją własną implementację, więc nie jest kompatybilny z kodem książki. Podzielę się moją, jeśli opublikujesz swoją próbę wdrożenia tego.

Edits:

NodeWeightPair

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; 
    } 
} 
+0

czy możesz pokazać klasy 'ArrayList' i' NodeWeightPair'? –

+0

Dodałem w 'NodeWeightPair'. 'ArrayList' to' java.util.ArrayList' – user2570465

+0

Twoja SpecialPQ przypomina bardziej stos priorytetowy ... Dlaczego wolisz ArrayList od, powiedzmy, LinkedList? –