All Downloads are FREE. Search and download functionalities are using the official Maven repository.

edu.princeton.cs.algs4.GlobalMincut Maven / Gradle / Ivy

The newest version!
/******************************************************************************
 *  Compilation:  javac GlobalMincut.java
 *  Execution:    java  GlobalMincut filename.txt
 *  Dependencies: EdgeWeightedGraph.java Edge.java UF.java 
 *                IndexMaxPQ.java FlowNetwork.java FlowEdge.java 
 *                FordFulkerson.java In.java StdOut.java
 *  Data files:   https://algs4.cs.princeton.edu/43mst/tinyEWG.txt
 *                https://algs4.cs.princeton.edu/43mst/mediumEWG.txt
 *
 *  Computes a minimum cut using Stoer-Wagner's algorithm.
 *
 *  % java GlobalMincut tinyEWG.txt 
 *    Min cut: 5 
 *    Min cut weight = 0.9500000000000001
 *    
 *  % java GlobalMincut mediumEWG.txt 
 *    Min cut: 25 60 63 96 199 237 
 *    Min cut weight = 0.14021
 *
 ******************************************************************************/

package edu.princeton.cs.algs4;

/**
 * The {@code GlobalMincut} class represents a data type for computing a
 * global minimum cut in an edge-weighted graph where the edge
 * weights are nonnegative. A cut is a partition of the set
 * of vertices of a graph into two nonempty subsets. An edge that has one
 * endpoint in each subset of a cut is a crossing edge. The weight
 * of a cut is the sum of the weights of its crossing edges.
 * A global minimum cut is a cut for which the weight is not
 * larger than the weight of any other cut.
 * 

* The {@code weight()} method returns the weight of the minimum cut and the * {@code cut(int v)} method determines if a vertex {@code v} is on the first or * on the second subset of vertices of the minimum cut. *

* This is an implementation of Stoer–Wagner's algorithm using an index * priority queue and the union-find data type in order to simplify dealing with * contracting edges. Precisely, the index priority queue is an instance of * {@link IndexMaxPQ} which is based on a binary heap. As a consequence, the * constructor takes O(V (V + E ) log * V ) time and O(V) extra space (not including the * graph), where V is the number of vertices and E is the * number of edges. However, this time can be reduced to O(V E * + V2 log V) by using an index priority queue * implemented using Fibonacci heaps. *

* Afterwards, the {@code weight()} and {@code cut(int v)} methods take constant * time. *

* For additional documentation, see *

    *
  • M. Stoer and F. Wagner (1997). A simple min-cut algorithm. Journal of * the ACM , 44(4):585-591. *
* * @author Marcelo Silva */ public class GlobalMincut { private static final double FLOATING_POINT_EPSILON = 1E-11; // the weight of the minimum cut private double weight = Double.POSITIVE_INFINITY; // cut[v] = true if v is on the first subset of vertices of the minimum cut; // or false if v is on the second subset private boolean[] cut; // number of vertices private int V; /** * This helper class represents the cut-of-the-phase. The * cut-of-the-phase is a minimum s-t-cut in the current graph, * where {@code s} and {@code t} are the two vertices added last in the * phase. */ private class CutPhase { private double weight; // the weight of the minimum s-t cut private int s; // the vertex s private int t; // the vertex t public CutPhase(double weight, int s, int t) { this.weight = weight; this.s = s; this.t = t; } } /** * Computes a minimum cut of an edge-weighted graph. * * @param G the edge-weighted graph * @throws IllegalArgumentException if the number of vertices of {@code G} * is less than {@code 2} or if anny edge weight is negative */ public GlobalMincut(EdgeWeightedGraph G) { V = G.V(); validate(G); minCut(G, 0); assert check(G); } /** * Validates the edge-weighted graph. * * @param G the edge-weighted graph * @throws IllegalArgumentException if the number of vertices of {@code G} * is less than {@code 2} or if any edge weight is negative */ private void validate(EdgeWeightedGraph G) { if (G.V() < 2) throw new IllegalArgumentException("number of vertices of G is less than 2"); for (Edge e : G.edges()) { if (e.weight() < 0) throw new IllegalArgumentException("edge " + e + " has negative weight"); } } /** * Returns the weight of the minimum cut. * * @return the weight of the minimum cut */ public double weight() { return weight; } /** * Returns {@code true} if the vertex {@code v} is on the first subset of * vertices of the minimum cut; or {@code false} if the vertex {@code v} is * on the second subset. * * @param v the vertex to check * @return {@code true} if the vertex {@code v} is on the first subset of * vertices of the minimum cut; or {@code false} if the vertex * {@code v} is on the second subset. * @throws IllegalArgumentException unless vertex {@code v} is between * {@code 0} and {@code (G.V() - 1)} */ public boolean cut(int v) { validateVertex(v); return cut[v]; } /** * Makes a cut for the current edge-weighted graph by partitioning its set * of vertices into two nonempty subsets. The vertices connected to the * vertex {@code t} belong to the first subset. Other vertices not connected * to {@code t} belong to the second subset. * * @param t the vertex {@code t} * @param uf the union-find data type */ private void makeCut(int t, UF uf) { for (int v = 0; v < cut.length; v++) { cut[v] = uf.connected(v, t); } } /** * Computes a minimum cut of the edge-weighted graph. Precisely, it computes * the lightest of the cuts-of-the-phase which yields the desired minimum * cut. * * @param G the edge-weighted graph * @param a the starting vertex */ private void minCut(EdgeWeightedGraph G, int a) { UF uf = new UF(G.V()); boolean[] marked = new boolean[G.V()]; cut = new boolean[G.V()]; CutPhase cp = new CutPhase(0.0, a, a); for (int v = G.V(); v > 1; v--) { cp = minCutPhase(G, marked, cp); if (cp.weight < weight) { weight = cp.weight; makeCut(cp.t, uf); } G = contractEdge(G, cp.s, cp.t); marked[cp.t] = true; uf.union(cp.s, cp.t); } } /** * Returns the cut-of-the-phase. The cut-of-the-phase is a minimum s-t-cut * in the current graph, where {@code s} and {@code t} are the two vertices * added last in the phase. This algorithm is known in the literature as * maximum adjacency search or maximum cardinality search. * * @param G the edge-weighted graph * @param marked the array of contracted vertices, where {@code marked[v]} * is {@code true} if the vertex {@code v} was already * contracted; or {@code false} otherwise * @param cp the previous cut-of-the-phase * @return the cut-of-the-phase */ private CutPhase minCutPhase(EdgeWeightedGraph G, boolean[] marked, CutPhase cp) { IndexMaxPQ pq = new IndexMaxPQ(G.V()); for (int v = 0; v < G.V(); v++) { if (v != cp.s && !marked[v]) pq.insert(v, 0.0); } pq.insert(cp.s, Double.POSITIVE_INFINITY); while (!pq.isEmpty()) { int v = pq.delMax(); cp.s = cp.t; cp.t = v; for (Edge e : G.adj(v)) { int w = e.other(v); if (pq.contains(w)) pq.increaseKey(w, pq.keyOf(w) + e.weight()); } } cp.weight = 0.0; for (Edge e : G.adj(cp.t)) { cp.weight += e.weight(); } return cp; } /** * Contracts the edges incidents on the vertices {@code s} and {@code t} of * the given edge-weighted graph. * * @param G the edge-weighted graph * @param s the vertex {@code s} * @param t the vertex {@code t} * @return a new edge-weighted graph for which the edges incidents on the * vertices {@code s} and {@code t} were contracted */ private EdgeWeightedGraph contractEdge(EdgeWeightedGraph G, int s, int t) { EdgeWeightedGraph H = new EdgeWeightedGraph(G.V()); for (int v = 0; v < G.V(); v++) { for (Edge e : G.adj(v)) { int w = e.other(v); if (v == s && w == t || v == t && w == s) continue; if (v < w) { if (w == t) H.addEdge(new Edge(v, s, e.weight())); else if (v == t) H.addEdge(new Edge(w, s, e.weight())); else H.addEdge(new Edge(v, w, e.weight())); } } } return H; } /** * Checks optimality conditions. * * @param G the edge-weighted graph * @return {@code true} if optimality conditions are fine */ private boolean check(EdgeWeightedGraph G) { // compute min st-cut for all pairs s and t // shortcut: s must appear on one side of global mincut, // so it suffices to try all pairs s-v for some fixed s double value = Double.POSITIVE_INFINITY; for (int s = 0, t = 1; t < G.V(); t++) { FlowNetwork F = new FlowNetwork(G.V()); for (Edge e : G.edges()) { int v = e.either(), w = e.other(v); F.addEdge(new FlowEdge(v, w, e.weight())); F.addEdge(new FlowEdge(w, v, e.weight())); } FordFulkerson maxflow = new FordFulkerson(F, s, t); value = Math.min(value, maxflow.value()); } if (Math.abs(weight - value) > FLOATING_POINT_EPSILON) { System.err.println("Min cut weight = " + weight + " , max flow value = " + value); return false; } return true; } // throw an IllegalArgumentException unless {@code 0 <= v < V} private void validateVertex(int v) { if (v < 0 || v >= V) throw new IllegalArgumentException("vertex " + v + " is not between 0 and " + (V-1)); } /** * Unit tests the {@code GlobalMincut} data type. * * @param args the command-line arguments */ public static void main(String[] args) { In in = new In(args[0]); EdgeWeightedGraph G = new EdgeWeightedGraph(in); GlobalMincut mc = new GlobalMincut(G); StdOut.print("Min cut: "); for (int v = 0; v < G.V(); v++) { if (mc.cut(v)) StdOut.print(v + " "); } StdOut.println(); StdOut.println("Min cut weight = " + mc.weight()); } } /****************************************************************************** * Copyright 2002-2018, Robert Sedgewick and Kevin Wayne. * * This file is part of algs4.jar, which accompanies the textbook * * Algorithms, 4th edition by Robert Sedgewick and Kevin Wayne, * Addison-Wesley Professional, 2011, ISBN 0-321-57351-X. * http://algs4.cs.princeton.edu * * * algs4.jar is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * algs4.jar is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with algs4.jar. If not, see http://www.gnu.org/licenses. ******************************************************************************/




© 2015 - 2025 Weber Informatics LLC | Privacy Policy