Nadesłany przez mephisto, 25 marca 2013 21:30
Kod przedstawiony poniżej przedstawia główną część rozwiązania problemu.Pobierz pełne rozwiązanie.
Jeżeli nie odpowiada Ci sposób formatowania kodu przez autora skorzystaj z pretty printer'a i dostosuj go automatycznie do siebie.
LazyPrimMinimumSpanningTree.java:
/** * Implementacja leniwej wersji algorytmu Prima do znajdowania minimalnego drzewa * rozpinajacego w spojnym nieskierowanym grafie. * * created by mephisto * www.algorytm.org */ import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.PriorityQueue; import java.util.Queue; /** * Krawedz grafu nieskierowanego. Zawiera informacje, ktore wierzcholki laczy * krawedz oraz zawiera jej wage(np. dlugosc, czas itd). * * @author mephisto */ class Edge implements Comparable<Edge> { // jeden wierzcholek private final int v; // drugi wierzcholek private final int w; // waga private final long weight; public Edge(int v, int w, int weight) { this.v = v; this.w = w; this.weight = weight; } /** * * @return jeden z wierzcholkow */ public int getEitherVertex() { return v; } /** * * @param vertex * jeden z wierzcholkow krawedzi * @return wierzcholek, ktory wspoltworzy krawedz z wierzcholkiem * {@code vertex} */ public int getOtherVertex(int vertex) { if (vertex == v) { return w; } else if (vertex == w) { return v; } throw new IllegalArgumentException("Wrong vertex!"); } /** * * @return wage krawedzi */ public long getWeight() { return weight; } @Override public String toString() { return String.format("%d->%d (%d) ", v, w, weight); } @Override public int compareTo(Edge arg) { if (getWeight() < arg.getWeight()) { return -1; } else if (getWeight() > arg.getWeight()) { return 1; } return 0; } } /** * Graf nieskierowany reprezentowany za pomoca list sasiedztwa danych * wierzcholkow. * * @author mephisto */ class Graph { // liczba wierzcholkow private final int v; // liczba krawedzi private int e; // listy sasiedztwa private List<Edge>[] adjacencyLists; @SuppressWarnings("unchecked") public Graph(int v) { this.v = v; this.e = 0; this.adjacencyLists = (List<Edge>[]) new List[v]; for (int i = 0; i < v; i++) { adjacencyLists[i] = new ArrayList<Edge>(); } } /** * * @return liczbe krawedzi w grafie */ public int getNumberOfEdges() { return e; } /** * * @return liczbe wierzcholkow w grafie */ public int getNumberOfVertices() { return v; } /** * Dodaje krawedz do odpowiednich list sasiedztwa(obu koncow krawedzi). * * @param edge * krawedz, ktora ma zostac dodana do grafu */ public void addEdge(Edge edge) { int v = edge.getEitherVertex(); int w = edge.getOtherVertex(v); adjacencyLists[v].add(edge); adjacencyLists[w].add(edge); e++; } /** * Zwraca liste sasiedztwa danego wierzcholka. * * @param v * indeks wierzcholka * @return zwraca iterowalna kolekcje krawedzi */ public Iterable<Edge> getAdjacencyList(int v) { return adjacencyLists[v]; } } public class LazyPrimMinimumSpanningTree { // zawiera flagi, czy dany wierzcholek zostal odwiedzony private boolean[] marked; // krawedzie minmalnego drzewa rozpinajacego private Queue<Edge> minimumSpanningTree; // krawedzie przekroju i krawedzie niewybieralne private Queue<Edge> priorityQueue; // sumaryczna waga drzewa private long weight; public LazyPrimMinimumSpanningTree(Graph graph) { marked = new boolean[graph.getNumberOfVertices()]; minimumSpanningTree = new LinkedList<Edge>(); priorityQueue = new PriorityQueue<Edge>(graph.getNumberOfVertices()); // odwiedzamy pierwszy wierzcholek visit(graph, 0); while (!priorityQueue.isEmpty()) { // pobieramy kolejna krawedz z kolejki priorytetowj Edge e = priorityQueue.poll(); int v = e.getEitherVertex(); int w = e.getOtherVertex(v); // jesli wierzcholki sa oznaczone jako odwiedzone pomijamy reszte // instrukcji if (marked[v] && marked[w]) { continue; } // dodajemy do drzewa rozpinajacego krawedz minimumSpanningTree.offer(e); // aktualizacja wagi drzewa rozpinajacego weight += e.getWeight(); // dodajemy do drzewa wierzcholki jesli sa nieodwiedzone if (!marked[v]) { visit(graph, v); } if (!marked[w]) { visit(graph, w); } } } /** * * @return iterowalna kolekcje krawedzi wyznaczonego drzewa */ public Iterable<Edge> edges() { return minimumSpanningTree; } public long getWeight() { return weight; } private void visit(Graph graph, int v) { // oznaczamy wierzcholek jako odwiedzony marked[v] = true; // dodajemy wszystkie nieodwiedzone sasiednie wierzcholki vierzcholka v // do kolejki priorytetowej for (Edge edge : graph.getAdjacencyList(v)) { if (!marked[edge.getOtherVertex(v)]) { priorityQueue.offer(edge); } } } /** * @param args */ public static void main(String[] args) { // Rozwiazanie przykladu z lekcji HEGARTYMATHS // http://www.youtube.com/watch?v=DqpmZiC3ito&list=PL7F1A69E79B5D6E3D Graph graph = new Graph(5); graph.addEdge(new Edge(0, 1, 6)); graph.addEdge(new Edge(0, 2, 4)); graph.addEdge(new Edge(0, 3, 8)); graph.addEdge(new Edge(0, 4, 2)); graph.addEdge(new Edge(1, 2, 5)); graph.addEdge(new Edge(1, 3, 8)); graph.addEdge(new Edge(1, 4, 6)); graph.addEdge(new Edge(2, 3, 9)); graph.addEdge(new Edge(2, 4, 4)); graph.addEdge(new Edge(3, 4, 7)); LazyPrimMinimumSpanningTree lazyPrimMST = new LazyPrimMinimumSpanningTree( graph); // krawedzie znalezionego drzewa for (Edge edge : lazyPrimMST.edges()) { System.out.println(edge); } System.out.println("Suma wag: " + lazyPrimMST.getWeight()); } }