题目描述
小B有n个下属,现小B要带着一些下属让别人拍照。
有m个人,每个人都愿意付给小B一定钱让n个人中的一些人进行合影。如果这一些人没带齐那么就不能拍照,小B也不会得到钱。
注意:带下属不是白带的!!!对于每个下属,如果他带了那么小B需要给他一些钱,保证当他拍照时配合。
请问,小B的净收益最多是多少。
输入输出格式
输入格式:
第1行有2个正整数m和n(0<m,n<=100)。接下来的m行,每行是一个要求拍照的人的有关数据。第一个数是他同意支付该合影的费用;接着是该合影需要的若干下属的编号,以一个0作为行的结束标记。最后一行的n个数是带每个下属的费用。
输出格式:
一个数,表示最大收益。小B可以一个人也不带。
输入输出样例
输入样例#1:
2 3 10 1 2 0 25 2 3 0 5 6 7
输出样例#1:
17
说明
对于10%的数据每个人都要求让全部n个人合影
对于30%的数据n<=15 m<=15
另有10%的数据答案为0
对于50%的数据n<=40 m<=40
另有10%的数据每个人只愿意拍一个人
对于100%的数据m,n<=100
额,思路就是最大权闭合子图。
m个请求与s连边,权值为方案价值;
n个员工与t连边,权值为员工花费;
方案与牵扯到的员工连边,权值为inf;
然后跑最大流,总流量就是最优方案的总花费;
附代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#define MAXN 210
#define MAX 999999999
using namespace std;
int n,m,s,t,c=2,res=0;
int head[MAXN],deep[MAXN];
struct node{
int next,to,w;
}a[MAXN*MAXN];
inline int read(){
int date=0,w=1;char c=0;
while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
return date*w;
}
void add(int u,int v,int w){
a[c].to=v;a[c].w=w;
a[c].next=head[u];
head[u]=c++;
a[c].to=u;a[c].w=0;
a[c].next=head[v];
head[v]=c++;
}
bool bfs(){
int u,v;
queue<int> q;
memset(deep,0,sizeof(deep));
deep[s]=1;
q.push(s);
while(!q.empty()){
u=q.front();
q.pop();
for(int i=head[u];i;i=a[i].next){
v=a[i].to;
if(a[i].w&&!deep[v]){
deep[v]=deep[u]+1;
if(v==t)return true;
q.push(v);
}
}
}
return false;
}
int dfs(int x,int limit){
if(x==t)return limit;
int v,sum,cost=0;
for(int i=head[x];i;i=a[i].next){
v=a[i].to;
if(a[i].w&&deep[v]==deep[x]+1){
sum=dfs(v,min(limit-cost,a[i].w));
if(sum>0){
a[i].w-=sum;
a[i^1].w+=sum;
cost+=sum;
if(cost==limit)break;
}
else deep[v]=-1;
}
}
return cost;
}
int dinic(){
int ans=0;
while(bfs())
ans+=dfs(s,MAX);
return ans;
}
int main(){
int u,v,w;
m=read();n=read();
s=0;t=n+m+1;
for(int i=1;i<=m;i++){
w=read();
res+=w;
add(s,i,w);
while(1){
u=read();
if(u==0)break;
add(i,u+m,MAX);
}
}
for(int i=1;i<=n;i++){
w=read();
add(i+m,t,w);
}
printf("%d\n",res-dinic());
return 0;
}