網絡流24題 P2762 太空飛行計划問題


網絡流24題 P2762 太空飛行計划問題

思路

問題模型:最大權閉合圖

轉化模型:網絡最小割

這道題是網絡流中一個比較重要的模型:最大權閉合圖轉最大流

建立超級源點\(S\)和超級匯點\(T\),然后每個實驗連一條從\(S\)到實驗,流量為實驗收益的邊,每個儀器連一條從儀器到\(T\), 流量為儀器耗費的邊,然后需要的儀器就連一條從實驗到儀器流量為\(inf\)(無窮大)的邊,因為實驗到儀器的邊的流量為正無窮,所以最小割一定不會在上面,根據最大流最小割定理,最大流就等於最小割,我們按照以上所說建圖,求出最大流,之后用實驗利益的總和減去最大流,得出的就是最大凈收益

最大流算法我用的是\(\text{Dinic}\)算法,因為這樣方便輸出,為什么?因為如果\(d[i]\)不為\(0\)就說明它一定用過,這樣就能方便輸出啦~

代碼

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int A = 1e5 + 11;
const int B = 1e6 + 11;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;

inline int read() {
	char c = getchar(); int x = 0, f = 1;
	for ( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
	return x * f;
}

int m, n, cnt, opt, S, T, ans, head[A], d[A], q[A];
struct node { int from, to, nxt, val; } e[A];

inline void add(int from, int to, int val) {
	e[cnt].to = to;
	e[cnt].val = val;
	e[cnt].nxt = head[from];
	head[from] = cnt++;
}

inline bool makelevel(int s, int t) {
	memset(d, 0, sizeof(d));
	memset(q, 0, sizeof(q));
	int l = 0, r = 0;
	d[s] = 1; q[r++] = s;
	while (l < r) {
		int x = q[l++];
		if (x == t) return true;
		for (int i = head[x]; i != -1; i = e[i].nxt) {
			int to = e[i].to;
			if (d[to] == 0 && e[i].val > 0) {
				d[to] = d[x] + 1;
				q[r++] = e[i].to;
			}
		}
	}
	return false;
}

int dfs(int x, int flow, int t) {
	if (x == t) return flow;
	int sum = 0;
	for (int i = head[x]; i != -1; i = e[i].nxt) {
		int to = e[i].to;
		if (d[to] == d[x] + 1 && e[i].val > 0) {
			int tmp = dfs(to, min(flow - sum, e[i].val), t);
			e[i].val -= tmp, e[i ^ 1].val += tmp;
			sum += tmp;
			if (sum == flow) return sum;
		}
	}
	return sum;
}

int main() {
	memset(head, -1, sizeof(head));
	m = read(), n = read();
	int S = 0, T = 555;
	int w, tot = 0, x;
	for (int i = 1; i <= m; i++) {
		scanf("%d", &w), tot += w;
		add(S, i, w), add(i, S, 0);
		while (getchar() == ' ') {
			scanf("%d", &x);
			add(i, x + m, inf);
			add(x + m, i, 0);
		}
	}
	for (int i = 1; i <= n; i++) {
		x = read();
		add(i + m, T, x), add(T, i + m, 0);
	}
	while (makelevel(S, T)) ans += dfs(S, inf, T);
	ans = tot - ans;
	for (int i = 1; i <= m; i++) if (d[i]) cout << i << ' '; puts("");
	for (int i = 1; i <= n; i++) if (d[i + m]) cout << i << ' '; puts("");
	cout << ans << '\n';
	return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM