summaryrefslogtreecommitdiff
path: root/graph/stoerWagner.cpp
blob: 655f5aa07d6edbf43499e96438631cf8867521a3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
struct edge {
	int from, to;
	ll cap;
};

vector<vector<edge>> adj, tmp;
vector<bool> erased;

void merge(int a, int b) {
	tmp[a].insert(tmp[a].end(), all(tmp[b]));
	tmp[b].clear();
	erased[b] = true;
	for (auto& v : tmp) {
		for (auto&e : v) {
			if (e.from == b) e.from = a;
			if (e.to == b) e.to = a;
}}}

ll stoer_wagner() {
	ll res = INF;
	tmp = adj;
	erased.assign(sz(tmp), false);
	for (int i = 1; i < sz(tmp); i++) {
		int s = 0;
		while (erased[s]) s++;
		priority_queue<pair<ll, int>> pq;
		pq.push({0, s});
		vector<ll> con(sz(tmp));
		ll cur = 0;
		vector<pair<ll, int>> state;
		while (!pq.empty()) {
			int c = pq.top().second;
			pq.pop();
			if (con[c] < 0) continue; //already seen
			con[c] = -1;
			for (auto e : tmp[c]) {
				if (con[e.to] >= 0) {//add edge to cut
					con[e.to] += e.cap;
					pq.push({con[e.to], e.to});
					cur += e.cap;
				} else if (e.to != c) {//remove edge from cut
					cur -= e.cap;
			}}
			state.push_back({cur, c});
		}
		int t = state.back().second;
		state.pop_back();
		if (state.empty()) return 0; //graph is not connected?!
		merge(state.back().second, t);
		res = min(res, state.back().first);
	}
	return res;
}