题目描述
小M在MC里开辟了两块巨大的耕地A和B(你可以认为容量是无穷),现在,小P有n中作物的种子,每种作物的种子有1个(就是可以种一棵作物)(用1...n编号)。
现在,第i种作物种植在A中种植可以获得ai的收益,在B中种植可以获得bi的收益,而且,现在还有这么一种神奇的现象,就是某些作物共同种在一块耕地中可以获得额外的收益,小M找到了规则中共有m种作物组合,第i个组合中的作物共同种在A中可以获得c1i的额外收益,共同总在B中可以获得c2i的额外收益。
小M很快的算出了种植的最大收益,但是他想要考考你,你能回答他这个问题么?
输入输出格式
输入格式:
第一行包括一个整数n
第二行包括n个整数,表示ai第三行包括n个整数,表示bi第四行包括一个整数m接下来m行,
对于接下来的第i行:第一个整数ki,表示第i个作物组合中共有ki种作物,
接下来两个整数c1i,c2i,接下来ki个整数,表示该组合中的作物编号。
输出格式:
只有一行,包括一个整数,表示最大收益
输入输出样例
说明
样例解释
A耕地种1,2,B耕地种3,收益4+2+3+2=11。
数据范围与约定
1<=k< n<= 1000,0 < m < = 1000 保证所有数据及结果不超过2*10^9。
//我还真以为这是个最大流板子。。。 //画图的时候发现,如果直接S向作物连INF的边,作物向A、B连各自收益的边,然后A、B向T连边的话, //。。。那肯定不对啊,因为一个作物可以有两种互不干扰的选择了。。 //那我们就让他们互相干扰,只能往一块地上种,怎么办呢? //S向农作物连种在A的收益,农作物向T连重在B的收益,这样就每种作物只能选一个了 //...但是这样出来是选的最小的。。。 话说网络流就是跑最小的。。。 //那我们一减就是最大的了。。 //。那这不是最小割吗。 //组合的情况怎么办呢? //新设两个点x和y //让S向x连在A种的边,边权为这个组合在A种获得的收益,x向组合内的作物连inf的边, //组合内作物向y连inf的边,y向T连在B种的边,边权为在B种获得的收益 //这样跑出来的最大流就是能获得的最小收益 //总收益减一下就是最大收益了 //好吧我无言以对,上午一直WA第二个点,气得我差点就特判A那个点了 //但是我没猜出那个点是啥来。。。 //好吧也不知道错误在哪 //下午来了,被班主任踢了两脚,敲另一个题的时候突然想起: //我要初始化num_edge=1 !!!!!! //不初始化的话,i^1就不是反向边了 刚学网络流发现要写num_edge=1的时候就预料到了肯定会翻车的 果不其然 //上午把这个题改成最大流板子跑样例,发现打错了 //改过来,过样例了,但是我没写num_edge=1,他仍然是错的。。。 //样例都是骗小孩的,我应该提交一次的 //所以,不要把时间卡在一道题上,上午的sb错误,放过它去,下午以来说不定就知道了 //(当然可能需要班主任触发) #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<queue> using namespace std; const int N=1e4+5; const int M=4e6+5; const int INF=0x7fffffff; int n,m,S,T,V; int head[N],front[N],num_edge; struct Edge { int v,flow,nxt; }edge[M]; inline int read() { char c=getchar();int num=0,f=1; for(;!isdigit(c);c=getchar()) f=c=='-'?-1:f; for(;isdigit(c);c=getchar()) num=num*10+c-'0'; return num*f; } inline void add_edge(int u,int v,int flow) { edge[++num_edge].v=v; edge[num_edge].flow=flow; edge[num_edge].nxt=head[u]; head[u]=num_edge; } int dep[N]; inline bool bfs() { // for(int i=1;i<=N;++i) // front[i]=head[i], memset(dep,0,sizeof(dep)); queue<int> que; que.push(S),dep[S]=1; int now,v; while(!que.empty()) { now=que.front(),que.pop(); for(int i=head[now];i;i=edge[i].nxt) { v=edge[i].v; if(!dep[v]&&edge[i].flow) { dep[v]=dep[now]+1; if(v==T) return 1; que.push(v); } } } return 0; } int dfs(int now,int flow) { if(now==T||!flow) return flow; int outflow=0,v,tmp; for(int i=head[now];i;i=edge[i].nxt) { if(edge[i].flow) { v=edge[i].v; if(dep[v]!=dep[now]+1) continue; tmp=dfs(v,min(flow,edge[i].flow)); flow-=tmp; outflow+=tmp; edge[i].flow-=tmp; edge[i^1].flow+=tmp; if(!flow) return outflow; } } dep[now]=0; return outflow; } int a; int main() { num_edge=1; n=read(); S=0,T=3005; for(int i=1;i<=n;++i) { a=read(); V+=a; add_edge(S,i,a); add_edge(i,S,0); } for(int i=1;i<=n;++i) { a=read(); V+=a; add_edge(i,T,a); add_edge(T,i,0); } m=read(); for(int i=1,k,c1,c2,id,P,Q,flow;i<=m;++i) { flow=0; P=i+n,Q=i+n+m; k=read(),c1=read(),c2=read(); V+=c1+c2; add_edge(S,P,c1); add_edge(P,S,0); add_edge(Q,T,c2); add_edge(T,Q,0); while(k--) { id=read(); add_edge(P,id,INF); add_edge(id,P,0); add_edge(id,Q,INF); add_edge(Q,id,0); } } while(bfs()) V-=dfs(S,INF); printf("%d",V); return 0; }