洛谷传送门
题目描述
小B有 n n 个下属,现小B要带着一些下属让别人拍照。
有个人,每个人都愿意付给小B一定钱让 n n 个人中的一些人进行合影。如果这一些人没带齐那么就不能拍照,小B也不会得到钱。
注意:带下属不是白带的!!!对于每个下属,如果他带了那么小B需要给他一些钱,保证当他拍照时配合。
请问,小B的净收益最多是多少。
输入输出格式
输入格式:
第行有 2 2 个正整数和 n n ()。接下来的 m m 行,每行是一个要求拍照的人的有关数据。第一个数是他同意支付该合影的费用;接着是该合影需要的若干下属的编号,以一个作为行的结束标记。最后一行的 n n 个数是带每个下属的费用。
输出格式:
一个数,表示最大收益。小B可以一个人也不带。
输入输出样例
输入样例#1:
2 3
10 1 2 0
25 2 3 0
5 6 7
输出样例#1:
17
说明
对于10%的数据每个人都要求让全部个人合影
对于30%的数据 n≤15,m≤15 n ≤ 15 , m ≤ 15
另有10%的数据答案为 0 0
对于50%的数据
另有10%的数据每个人只愿意拍一个人
对于100%的数据 m,n≤100 m , n ≤ 100
解题分析
很容易想到网络流, 但边权又有正又有负怎么搞?
其实很简单的转化:先假设我们会满足所有人的需求, 再考虑割边。
即:我们从源点 S S 向每个要求连容量为收益的边, 再从这些点向合影的人连容量为的边, 所有合影的人向汇点 T T 连容量为花费绝对值的边。
因为中间的边无法割掉, 所以跑最小割时有两种情况:
- 和要求之间的边被割掉: 等价于我们舍弃了这个顾客不要他的收益了。
- T T 和合影者的边被割掉: 等价于我们愿意支付给他工资来保全前面的收益。
综上, 最终答案为最小割。
代码如下:
#include <cstdio> #include <cstring> #include <cctype> #include <cmath> #include <cstdlib> #include <algorithm> #include <queue> #define R register #define IN inline #define gc getchar() #define W while #define MX 400005 #define S 0 #define T 1000 #define INF 100000000 template <class TT> IN void in(TT &x) { x = 0; R char c = gc; W (!isdigit(c)) c = gc; W (isdigit(c)) x = (x << 1) + (x << 3) + c - 48, c = gc; } struct Edge{int to, fl, nex;} edge[MX << 1]; int cnt = -1, dot, req; int head[10005], layer[10005]; std::queue <int> q; IN void add(R int from, R int to, R int fl) {edge[++cnt] = {to, fl, head[from]}, head[from] = cnt;} IN bool BFS() { std::memset(layer, 0, sizeof(layer)); q.push(S); layer[S] = 1; R int now; W (!q.empty()) { now = q.front(); q.pop(); for (R int i = head[now]; ~i; i = edge[i].nex) { if(edge[i].fl && !layer[edge[i].to]) { layer[edge[i].to] = layer[now] + 1; q.push(edge[i].to); } } } return layer[T]; } int DFS(R int now, R int val) { if(now == T) return val; int buf, lef = val; for (R int i = head[now]; ~i; i = edge[i].nex) { if((layer[edge[i].to] != layer[now] + 1) || !edge[i].fl) continue; buf = DFS(edge[i].to, std::min(lef, edge[i].fl)); if(!buf) continue; edge[i].fl -= buf, edge[i ^ 1].fl += buf; lef -= buf; if(lef <= 0) return val; } return val - lef; } long long Dinic() { long long ret = 0; W (BFS()) ret += DFS(S, INF); return ret; } int main(void) { int buf; long long tot = 0; in(req), in(dot); std::memset(head, -1, sizeof(head)); for (R int i = 1; i <= req; ++i) { in(buf); add(S, i, buf), add(i, S, 0); tot += buf; W (233) { in(buf); if(!buf) break; add(i, buf + req, INF), add(buf + req, i, 0); } } for (R int i = 1; i <= dot; ++i) in(buf), add(i + req, T, buf), add(T, i + req, 0); printf("%lld", tot - Dinic()); }