[lnsyoj2610/luoguP2762] 太空飞行计划问题
题意
有 \(n\) 种实验,\(m\) 种器材,第 \(i\) 种实验需要器材集合为 \(R_i\),完成第 \(i\) 种实验可以获得 \(w_i\) 元,使用第 \(i\) 种器材需要 \(c_i\) 元,求最大利润。
sol
将实验作为左部点,器材作为右部点,根据依赖关系连边,左部连边奖金,右部连边成本。
记选择做的实验收益和为 \(A\),选择不做的实验收益和为 \(B\),选择的器材成本为 \(a\),不选择的器材成本为 \(b\),则最小割为 \(B + a\),那么使用总收益-最小割即为 \(A + B - B -a=A-a\)。
代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
const int N = 105, M = 6005, INF = 0x3f3f3f3f;
int h[N], e[M], cap[M], ne[M], idx;
int d[N], cur[N];
int n, S, T;
int nn, m;
int exprc[N], expr[N][N], cost[N];
char s[205];
bool st[N];
void add(int a, int b, int c){
e[idx] = b, cap[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
e[idx] = a, cap[idx] = 0, ne[idx] = h[b], h[b] = idx ++ ;
}
void build(){
memset(h, -1, sizeof h);
n = nn + m + 2;
S = n - 1, T = n;
for (int i = 1; i <= nn; i ++ ) add(S, i, exprc[i]);
for (int i = 1; i <= m; i ++ ) add(nn + i, T, cost[i]);
for (int i = 1; i <= nn; i ++ )
for (int j = 1; j <= expr[i][0]; j ++ )
add(i, nn + expr[i][j], INF);
}
void print() {
for (int i = 1; i <= nn; i ++ ) if (~d[i]) {
printf("%d ", i);
for (int j = 1; j <= expr[i][0]; j ++ )
st[expr[i][j]] = true;
}
puts("");
for (int i = 1; i <= m; i ++ )
if (st[i])
printf("%d ", i);
puts("");
}
bool bfs(){
queue<int> q;
memset(d, -1, sizeof d);
d[S] = 0, q.push(S), cur[S] = h[S];
while (!q.empty()) {
int t = q.front();
q.pop();
for (int i = h[t]; ~i; i = ne[i]){
int j = e[i];
if (d[j] == -1 && cap[i]) {
d[j] = d[t] + 1;
cur[j] = h[j];
if (j == T) return true;;
q.push(j);
}
}
}
return false;
}
int find(int u, int limit){
if (u == T) return limit;
int flow = 0;
for (int i = cur[u]; ~i && flow < limit; i = ne[i]){
int j = e[i];
cur[u] = i;
if (d[j] == d[u] + 1 && cap[i]){
int t = find(j, min(cap[i], limit - flow));
if (!t) d[t] = -1;
cap[i] -= t; cap[i ^ 1] += t; flow += t;
}
}
return flow;
}
int dinic(){
int r = 0, flow;
while (bfs()) while (flow = find(S, INF)) r += flow;
return r;
}
int main(){
scanf("%d%d", &nn, &m);
int sum = 0;
for (int i = 1; i <= nn; i ++ ) {
scanf("%d", &exprc[i]);
sum += exprc[i];
memset(s, 0, sizeof s);
cin.getline(s, 200);
int ulen = 0, t;
while (sscanf(s + ulen, "%d", &t) == 1) {
expr[i][ ++ expr[i][0]] = t;
if (!t) ulen ++ ;
else
while (t) t /= 10, ulen ++ ;
ulen ++ ;
}
}
for (int i = 1; i <= m; i ++ ) scanf("%d", &cost[i]);
build();
int t = dinic();
print();
printf("%d\n", sum - t);
}

浙公网安备 33010602011771号