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 MBSubmit: 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
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。