感觉自己好菜啊,给网络流大佬门跪了。当时比赛的时候板子错了,细思极恐。
补题传送门:点击打开链接
图的编号:
产品1--n
矿n+1--n+m
源点n+m+1
汇点n+m+2
连图的时候源点连产品,容量为价值,汇点连矿场,容量为消耗,其他的容量为info
跑一次最大流,用总价值一减就是答案。
(当然你也可以倒着连,比赛的时候我是倒着连的,然后,板子错了,你们懂的)
#include
using namespace std;
const int maxn=20000;
const int info=2e10+7;
struct Edge{//大白的dinic板子
int from,to,cap,flow;
};
vectorG[maxn];
bool vis[maxn];
int d[maxn];
int cur[maxn];
int S,T;
vectoredges;
void init(int N){//初始化
for (int i=0;i Q;
Q.push(s);
d[s]=0;
vis[s]=1;
while(!Q.empty()){
int x = Q.front();Q.pop();
for (int i=0;ie.flow){
vis[e.to]=1;
d[e.to]=d[x]+1;
Q.push(e.to);
}
}
}
return vis[t];
}
long long DFS(int x,int a){
if (x==T||a==0)return a;
long long f,flow=0;
for (int &i = cur[x];i0){
e.flow+=f;
edges[G[x][i]^1].flow -=f;
flow +=f;
a-=f;
if (a==0)break;
}
}
return flow;
}
long long Maxflow(int s,int t){
long long flow=0;
while (BFS(s,t)){
memset(cur,0,sizeof(cur));
flow+=DFS(s,info);
}
return flow;
}
int M[maxn],N[maxn];
int main(){
int t;scanf("%d",&t);
while(t--){
int n;int m;
scanf("%d%d",&n,&m);
S=n+m+1;T=n+m+2;
init(n+m+3);
long long ans=0;
for (int i=1;i<=n;i++){
scanf("%d",&N[i]);
ans+=N[i];
}
for (int i=1;i<=m;i++)scanf("%d",&M[i]);
for (int i=1;i<=n;i++){
int a,b;scanf("%d%d",&a,&b);
int te;
while (a--){
scanf("%d",&te);
AddEdge(i,te+n,info);//
}
while (b--){
scanf("%d",&te);
AddEdge(i,te,info);
}
}
for (int i=1;i<=n;i++){
AddEdge(m+n+1,i,N[i]);
}
for (int i=1;i<=m;i++){
AddEdge(n+i,m+n+2,M[i]);
}
long long te=Maxflow(m+n+1,m+n+2);
ans=ans-te;
printf("%lld\n",ans);
//printf("%d\n",te);
}
return 0;
}