[洛谷 P1361] 小M的作物
题目链接
大致题意:
懒癌
题是好题,题解不算是好题解
解题思路:
对于每一株作物,仅能种在 A/B 的一块田地里,也就是二选一
如果只有一个作物,我们肯定选择种在A或者种在B两者中最大的一条边,删掉小边
那多个作物呢,同理,去掉最小边,使其分成两个不相通的集合,到这里,不就是求最小割吗?
但是较为麻烦的是额外的收益怎么处理呢
对于这种情况,我们将这个组合里所有点作为一个点集,根据AB区,分别连向s,t,建立一个新点x
用s连向x,即
同样,建立一个新点y,连向t
为了保证割边时,只会割s->x或者y->t的边,把x,y连向点集的边设为INF
求最大的收益,即总收益-最小割
AC代码:
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 1; i <= (n); ++i)
using namespace std;
typedef pair<int, int> PII;
typedef long long ll;
const int N = 1e6 + 10, M = 2e6 + 10, INF = 1e9 + 7;
int n, m, s, t;
int h[N], e[M], ne[M], f[M], idx;
int dep[N], cur[N];
void add(int a, int b, int c) {
e[idx] = b, f[idx] = c, ne[idx] = h[a], h[a] = idx++;
e[idx] = a, f[idx] = 0, ne[idx] = h[b], h[b] = idx++;
}
bool bfs() {
memset(dep, -1, sizeof dep);
queue<int>q;
q.push(s); dep[s] = 0; cur[s] = h[s];
while (!q.empty()) {
int u = q.front(); q.pop();
for (int i = h[u]; ~i; i = ne[i]) {
int v = e[i];
if (dep[v] == -1 && f[i]) {
dep[v] = dep[u] + 1;
cur[v] = h[v];
if (v == t)return true;
q.push(v);
}
}
}
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]) {
cur[u] = i;
int v = e[i];
if (dep[v] == dep[u] + 1 && f[i]) {
int tmp = find(v, min(f[i], limit - flow));
if (!tmp)dep[v] = -1;
f[i] -= tmp; f[i ^ 1] += tmp; flow += tmp;
}
}
return flow;
}
int dinic() {
int res = 0, flow;
while (bfs())
while (flow = find(s, INF))
res += flow;
return res;
}
int main(void)
{
memset(h, -1, sizeof h);
cin >> n; s = 0, t = n + 1;
int sum = 0;
for (int i = 1; i <= n; ++i) {
int x; cin >> x; sum += x;
add(s, i, x); add(i, s, 0);
}
for (int i = 1; i <= n; ++i) {
int x; cin >> x; sum += x;
add(i, t, x); add(t, i, 0);
}
cin >> m;
for (int i = 1; i <= m; ++i) {
int w1, w2, cnt; cin >> cnt >> w1 >> w2;
sum += w1 + w2;
add(s, n + 10 + 2 * i - 1, w1);
add(n + 10 + 2 * i, t, w2);
while (cnt--) {
int x; cin >> x;
add(n + 10 + 2 * i - 1, x, INF);
add(x, n + 10 + 2 * i, INF);
}
}
int res = sum - dinic();
cout << res << endl;
return 0;
}
- i - 1, x, INF);
add(x, n + 10 + 2 * i, INF);
}
}
int res = sum - dinic();
cout << res << endl;
return 0;
}