参考博客:https://www.cnblogs.com/dilthey/p/7565206.html
题意:T组样例。n种产品,m个矿场。制造每种产品都需要一些其他产品和矿石。制造一种产品会获得val的收益,开采一个矿场需要花费cost,矿场一旦开采就能获得无穷多的矿石。问净收益的最大值。
结论:
1、最大点权闭合子图的值等于正点权和-最小割。
2、最大点权闭合子图中的节点的后继节点都在该子图中。
思路:正权点和源点连边容量为权值,负权点和汇点连边容量也为权值,为相反数也就是正的,其余边容量都为inf。跑一遍最大流后,用正权和减去最大流即可。
#include <bits/stdc++.h>
#define ll long long
#define int long long
using namespace std;
const int N = 1e3+10;
const int M = 1e6+10;
const int inf = 0x3f3f3f3f3f3f3f3fLL;
struct node
{
int to,ca,next;
}g[M];
int head[N],deep[N],cur[N],q[N],he,ta,cnt,a[210],b[210];
int n,m,s,t;
void Init()
{
cnt=0;
memset(head,-1,sizeof(head));
//for(int i=1;i<=n;i++)
//head[i]=-1;
return ;
}
void add(int u,int v,int w)
{
g[cnt].to=v;
g[cnt].ca=w;
g[cnt].next=head[u];
head[u]=cnt++;
return ;
}
bool bfs()
{
memset(deep,0,sizeof(deep));
//for(int i=1;i<=n;i++)
//deep[i]=0;
he=ta=0;
int u,v;
q[ta++]=s;
deep[s]=1;//别漏了!!!!!!!!!!!!!!!!
while(he!=ta)
{
u=q[he++];
//cout<<u<<endl;
if(u==t) return 1;
for(int i=head[u];i!=-1;i=g[i].next)
{
v=g[i].to;
if(g[i].ca>0&&!deep[v])
{
deep[v]=deep[u]+1;
q[ta++]=v;
}
}
}
return deep[t]!=0;
}
int dfs(int u,int flow)
{
//cout<<u<<endl;
if(u==t||!flow) return flow;
int ans=0,nowflow,v;
for(int& i=cur[u];i!=-1;i=g[i].next)
{
v=g[i].to;
if(g[i].ca>0&&deep[v]==deep[u]+1)
{
nowflow=dfs(v,min(flow,g[i].ca));
if(nowflow)
{
ans+=nowflow;
flow-=nowflow;
g[i].ca-=nowflow;
g[i^1].ca+=nowflow;
if(!flow) break;
}
}
}
if(!ans) deep[u]=0;
return ans;
}
int Dinic()
{
int maxflow=0,flow;
while(bfs())
{
memcpy(cur,head,sizeof(head));
//for(int i=1;i<=n;i++)
//cur[i]=head[i];
while(flow=dfs(s,inf))
{
//cout<<flow<<endl;
maxflow+=flow;
}
}
//cout<<maxflow<<endl;
return maxflow;
}
signed main(void)
{
int T;
scanf("%lld",&T);
while(T--)
{
int sum=0;
scanf("%lld%lld",&n,&m);
s=0,t=n+m+1;
Init();
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
sum+=a[i];
add(s,i,a[i]);
add(i,s,0);
}
for(int i=1;i<=m;i++)
{
scanf("%lld",&b[i]);
add(i+n,t,b[i]);
add(t,i+n,0);
}
for(int i=1;i<=n;i++)
{
int k1,k2,x;
scanf("%lld%lld",&k1,&k2);
for(int j=1;j<=k1;j++)
{
scanf("%lld",&x);
add(i,x+n,inf);
add(x+n,i,0);
}
for(int j=1;j<=k2;j++)
{
scanf("%lld",&x);
add(i,x,inf);
add(x,i,0);
}
}
printf("%lld\n",sum-Dinic());
}
return 0;
}