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

posted @ 2015-08-29 10:16  JSZX11556  阅读(247)  评论(0编辑  收藏  举报