#include <iostream>
#include <vector>
#include <time.h>
#include <limits.h>
#include <math.h>
using namespace std;
struct Edge
{
int src;
int dest;
Edge(int s, int d) : src(s), dest(d) {}
};
struct Graph
{
int V; // number of vertices
vector<Edge> egdes;
};
// disjoint-set
struct subset
{
int parent;
int rank = 0;
};
// find with path compression
int _find(subset subsets[], int i)
{
// path compression
if (subsets[i].parent != i)
subsets[i].parent = _find(subsets, subsets[i].parent);
return subsets[i].parent;
}
// union by rank
void _union(subset subsets[], int x, int y)
{
int xroot = _find(subsets, x);
int yroot = _find(subsets, y);
if (xroot == yroot)
return;
// attach smaller rank tree as subtree of higer rank tree
if (subsets[xroot].rank < subsets[yroot].rank)
subsets[xroot].parent = yroot;
else if (subsets[xroot].rank > subsets[yroot].rank)
subsets[yroot].parent = xroot;
else
{
subsets[xroot].parent = yroot;
++subsets[yroot].rank;
}
}
// Karger could return the global min-cut with probability >= 1/(n^2)
int Karger(const Graph &graph, vector<int> &index)
{
int V = graph.V;
int E = graph.egdes.size();
subset *subsets = new subset[V];
for (int i = 0; i != V; ++i)
{
subsets[i].parent = i;
subsets[i].rank = 0;
}
int vertices = V;
while (vertices > 2)
{
// pick a random edge
int i = rand() % E;
int subset1 = _find(subsets, graph.egdes[i].src);
int subset2 = _find(subsets, graph.egdes[i].dest);
// two points belong to same subset
if (subset1 == subset2)
continue;
// contract the edge
--vertices;
_union(subsets, subset1, subset2);
}
index.clear();
int cutedges = 0;
for (int i = 0; i != E; ++i)
{
if (_find(subsets, graph.egdes[i].src) != _find(subsets, graph.egdes[i].dest))
{
++cutedges;
index.push_back(i);
}
}
return cutedges;
}
// n^2ln(n) times repeat, the probability of failing to find min-cut <= 1/(n^2)
void amplify(const Graph &graph, vector<Edge> &edges)
{
srand(time(NULL));
int cutedges = INT_MAX;
double V = graph.V;
int loops = static_cast<int>(V * V * log(V));
for (int i = 0; i != loops; ++i)
{
vector<int> index;
if (Karger(graph, index) < cutedges)
{
edges.clear();
for (int j = 0; j != index.size(); ++j)
edges.push_back(graph.egdes[index[j]]);
cutedges = index.size();
}
else
index.clear();
}
}
int main()
{
Graph graph;
graph.V = 6;
graph.egdes.push_back(Edge(0, 1));
graph.egdes.push_back(Edge(0, 5));
graph.egdes.push_back(Edge(0, 2));
graph.egdes.push_back(Edge(1, 5));
graph.egdes.push_back(Edge(1, 2));
graph.egdes.push_back(Edge(1, 3));
graph.egdes.push_back(Edge(2, 3));
graph.egdes.push_back(Edge(3, 4));
graph.egdes.push_back(Edge(4, 5));
vector<Edge> edges;
amplify(graph, edges);
cout << "Global Min-Cut: " << edges.size() << endl;
for (auto a : edges)
cout << a.src << " to " << a.dest << endl;
system("PAUSE");
}
Reference:
http://www.cc.gatech.edu/~vigoda/7530-Spring10/Kargers-MinCut.pdf