BZOJ 4177: Mike的农场( 最小割 )

时间:2023-03-08 16:58:00

BZOJ 4177: Mike的农场( 最小割 )

显然是最小割...

对于规律(i, j, k) i,j 互相连边, 容量为k

对于规则(S, a, b) 新建一个点x, x与S中每个点连一条弧, 容量+∞, 然后再根据a决定x与源点或汇点连边.

跑最大流, 用总收益减去就是答案了...挺好想的一道题...

#include<bits/stdc++.h>

using namespace std;

const int maxn = 10100;
const int INF = 10000000; struct edge {
int to, cap;
edge *next, *rev;
} E[1000000], *pt = E, *head[maxn]; inline void add(int u, int v, int w) {
pt->to = v; pt->cap = w;
pt->next = head[u]; head[u] = pt++;
}
inline void addedge(int u, int v, int w) {
add(u, v, w); add(v, u, 0);
head[u]->rev = head[v];
head[v]->rev = head[u];
} int S, T, N, cnt[maxn], h[maxn];
edge *cur[maxn], *p[maxn]; int maxFlow() {
memset(cnt, 0, sizeof cnt); cnt[0] = N;
memset(h, 0, sizeof h);
for(int i = 0; i < N; i++) cur[i] = head[i];
edge* e;
int flow = 0;
for(int x = S, A = INF; h[S] < N; ) {
for(e = cur[x]; e; e = e->next)
if(e->cap && h[e->to] + 1 == h[x]) break;
if(e) {
cur[x] = p[e->to] = e;
A = min(A, e->cap);
x = e->to;
if(x == T) {
for(; x != S; x = p[x]->rev->to) {
p[x]->cap -= A;
p[x]->rev->cap += A;
}
flow += A;
A = INF;
}
} else {
if(!--cnt[h[x]]) break;
h[x] = N;
for(e = head[x]; e; e = e->next) if(e->cap && h[e->to] + 1 < h[x]) {
h[x] = h[e->to] + 1;
cur[x] = e;
}
cnt[h[x]]++;
if(x != S) x = p[x]->rev->to;
}
}
return flow;
} int main() { int ans = 0;
int n, m, k; scanf("%d%d%d", &n, &m, &k);
S = 0; T = n + k + 1; N = T + 1;
for(int i = 1; i <= n; i++) {
int t; scanf("%d", &t);
ans += t;
addedge(S, i, t);
}
for(int i = 1; i <= n; i++) {
int t; scanf("%d", &t);
ans += t;
addedge(i, T, t);
}
while(m--) {
int u, v, w; scanf("%d%d%d", &u, &v, &w);
addedge(u, v, w); addedge(v, u, w);
}
for(int i = 1; i <= k; i++) {
int t, a, b; scanf("%d%d%d", &t, &a, &b);
ans += b;
if(a) {
while(t--) {
int h; scanf("%d", &h);
addedge(h, n + i, INF);
}
addedge(n + i, T, b);
} else {
while(t--) {
int h; scanf("%d", &h);
addedge(n + i, h, INF);
}
addedge(S, n + i, b);
}
}
printf("%d\n", ans - maxFlow()); return 0;
}

  

4177: Mike的农场

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 163  Solved: 111
[Submit][Status][Discuss]

Description

Mike有一个农场,这个农场n个牲畜围栏,现在他想在每个牲畜围栏中养一只动物,每只动物可以是牛或羊,并且每个牲畜围栏中的饲养条件都不同,其中第i个牲畜围栏中的动物长大后,每只牛可以卖a[i]元,每只羊可以卖b[i]元,为了防止牛羊之间相互影响,Mike找到了m条规律,每条规律给出一个三元组(i, j, k)表示如果第i个围栏和第j个围栏养的是不同的动物,那么Mike就需要花费k的代价请人帮忙处理牛羊之间的影响。不过同时Mike也发现k条特殊的规则(S, a, b),表示如果S中所有牲畜围栏中都养的是动物a,那么Mike可以获得b的额外收入。现在Mike想知道他该在哪些围栏中饲养什么动物才能使得总收益最大,为了简化问题,你只需要输出最大收益。

Input

第一行三个整数n、m、k,表示一共有n个围栏,m条规律,k条规则。

第二行有n个整数,表示a[i]。

第三行有n个整数,表示b[i]。

接下来m行,每行有三个整数(i, j, k)表示一条规则。

再接下来k行,每行一开始有三个整数t、a和b,表示一条规则(S, a, b),其中S的大小为t,接下来

t个整数表示S中的元素(a为0表示全为牛,a为1表示全为羊)。

Output

输出一个整数ans,表示最大收益。

Sample Input

4 2 1
1 2 3 1
2 3 1 2
1 2 3
1 3 2
2 0 100 1 2

Sample Output

108

HINT

对于100的数据,n <= 5000, m <= 5000, k <= 5000, a = 0 or 1。

Source