题目来自:点击这里
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
const int maxm=2000100;
const int maxd=2000100;
const int inf=0x7ffffff;
using namespace std;
int n;
int tot=0;
int edge_num=1;
//0 做源点 0-n+1为中间节点 n+1 做汇点 n+2 - n+1+2m为虚拟节点
//反向建一个无穷的边,则这条边不会被割掉
int cur[maxd];
struct Edge{
int to;
int w;
int next;
}edge[maxm];
int head[maxd];
int dep[maxd];
inline void addedge(int from,int to,int dis){
edge[++edge_num].next=head[from],edge[edge_num].to=to,edge[edge_num].w=dis,head[from]=edge_num;
edge[++edge_num].next=head[to],edge[edge_num].to=from,edge[edge_num].w=0,head[to]=edge_num;
}
bool bfs(){
//dinic算法用bfs分层
memset(dep,-1,sizeof(dep));
memcpy(cur,head,sizeof(head));
queue<int>q;
q.push(0);//0作为源点
dep[0]=0;//深度为0
int u,v;
while(!q.empty()){
u=q.front();
q.pop();
for(int i=head[u];i;i=edge[i].next){
v=edge[i].to;
if(dep[v]==-1&&edge[i].w>0){
dep[v]=dep[u]+1;
q.push(v);
}
}
}
return (dep[n+1]!=-1);
}
int dfs(int u,int flow){
//dfs求増广路 ,u是当前节点,flow是当前流量
if(u==n+1) return flow;//到达汇点,返回
int flowsum=0,flowmin;
for(int i=cur[u];i;i=edge[i].next){
//遍历与u 相连的所有节点
cur[u]=i;
int v=edge[i].to;
if(dep[v]==dep[u]+1&&edge[i].w>0){
//满足层次且流量大于0
flowmin=dfs(v,min(flow,edge[i].w));//flowmin表示该増广路中拥有最小流量的边的流量
flow-=flowmin;//当前流量
edge[i].w-=flowmin;//每条边的权都减去该增广路中拥有最小流量的边的流量
flowsum+=flowmin;//要求的总流量
edge[i^1].w+=flowmin;//将每条边的反向边的权增加这个值
if(!flow) break;
}
}
return flowsum;
}
int dinic(){
int max_flow = 0;
while (bfs()){
max_flow += dfs(0, inf);
}
return max_flow;
}
int main() {
scanf("%d",&n);
for(int i=1;i<=n;++i){
int t;
scanf("%d",&t);
tot+=t;
addedge(0,i,t);
}
for(int i=1;i<=n;++i){
int t;
scanf("%d",&t);
tot+=t;
addedge(i,n+1,t);
}
int m;
scanf("%d",&m);
for(int i=1;i<=m;++i){
//继续建边
int k,c1,c2;
scanf("%d%d%d",&k,&c1,&c2);
tot+=c1+c2;
addedge(0,i+1+n,c1);//这个组合种在A有c1的收益
addedge(i+1+n+m,n+1,c2);//种在B有c2的收益
for(int j=1;j<=k;++j){
int t;
scanf("%d",&t);
addedge(i+1+n,t,inf);
addedge(t,i+1+m+n,inf);
}
}
int anse=dinic();
printf("%d",tot-anse);
return 0;
}