Karger's algorithm to solve global min-cut

本文介绍了一种使用Karger算法寻找无向图全局最小割的方法。通过随机选择边进行收缩,结合并查集实现顶点合并,重复多次实验以提高找到最小割的概率。文章详细展示了算法的具体实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值