[bzoj3438]小M的作物 最小割

3438: 小M的作物

Time Limit: 10 Sec   Memory Limit: 256 MB
Submit: 1349   Solved: 578
[ Submit][ Status][ Discuss]

Description

小M在MC里开辟了两块巨大的耕地A和B(你可以认为容量是无穷),现在,小P有n中作物的种子,每种作物的种子
有1个(就是可以种一棵作物)(用1...n编号),现在,第i种作物种植在A中种植可以获得ai的收益,在B中种植
可以获得bi的收益,而且,现在还有这么一种神奇的现象,就是某些作物共同种在一块耕地中可以获得额外的收益
,小M找到了规则中共有m种作物组合,第i个组合中的作物共同种在A中可以获得c1i的额外收益,共同总在B中可以
获得c2i的额外收益,所以,小M很快的算出了种植的最大收益,但是他想要考考你,你能回答他这个问题么?

Input

第一行包括一个整数n
第二行包括n个整数,表示ai第三行包括n个整数,表示bi第四行包括一个整数m接下来m行,
对于接下来的第i行:第一个整数ki,表示第i个作物组合中共有ki种作物,
接下来两个整数c1i,c2i,接下来ki个整数,表示该组合中的作物编号。输出格式

Output

只有一行,包括一个整数,表示最大收益

Sample Input

3
4 2 1
2 3 2
1
2 3 2 1 2

Sample Output

11
样例解释A耕地种1,2,B耕地种3,收益4+2+3+2=11。
1<=k< n<= 1000,0 < m < = 1000 保证所有数据及结果不超过2*10^9。

HINT

Source

具体看代码,话说最大闭合权子图什么的,表示没想到

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define INF 0x7fffffff
using namespace std;
const int N = 4005;
int last[N],S,T,n,m,h[N],q[N],cnt=1,cur[N],b[N],ans,MT,a[N],sum;
struct Edge{
	int to,next,v;
}e[2100005];
void insert( int u, int v, int w ){
	e[++cnt].to = v; e[cnt].next = last[u]; e[cnt].v = w; last[u] = cnt;
	e[++cnt].to = u; e[cnt].next = last[v]; e[cnt].v = 0; last[v] = cnt;
}
bool bfs(){
	memset(h,-1,sizeof(h));
	int tail = 1, head = 0;
	q[0] = 0; h[0] = 0;
	while( tail != head ){
		int now = q[head++];
		for( int i = last[now]; i; i = e[i].next )
			if( h[e[i].to] == -1 && e[i].v ){
				h[e[i].to] = h[now] + 1;
				q[tail++] = e[i].to;
			}
	}
	return h[T] != -1;
}
int dfs( int x, int f ){
	int w,used=0;
	if( x == T ) return f;
	for( int i = cur[x]; i; i = e[i].next )
		if( h[e[i].to] == h[x] + 1 ){
			w = dfs(e[i].to,min(e[i].v,f-used));
			e[i].v -= w; e[i^1].v += w; used += w;
			if( e[i].v ) cur[x] = i; if( f == used ) return f;
		}
	if( !used ) h[x] = -1;
	return used;
}
void dinic(){
	while( bfs() ){
		for( int i = S; i <= T; i++ ) cur[i] = last[i];
		ans += dfs(S,INF);
	}
}
int main(){
	scanf("%d", &n);
	for( int i = 1; i <= n; i++ ) scanf("%d", &a[i]), sum += a[i];
	for( int i = 1; i <= n; i++ ) scanf("%d", &b[i]), sum += b[i];
	scanf("%d", &m);
	S = 0; T = n+2*m+1;
	for( int i = 1; i <= n; i++ ) insert(S,i,b[i]), insert(i,T,a[i]);
	for( int i = 1; i <= m; i++ ){
		int k,c1,c2;
		scanf("%d%d%d", &k, &c1, &c2);
		insert(S,n+i*2,c2);
		insert(n+i*2-1,T,c1);
		sum += c1+c2;
		for( int j = 1,x; j <= k; j++ ){
			scanf("%d", &x);
			insert(x,n+i*2-1,INF);
			insert(n+i*2,x,INF);
		}
	}
	dinic();
	printf("%d", sum - ans);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值