洛谷P3410 拍照

来源:互联网 发布:b站mac客户端 编辑:程序博客网 时间:2024/06/09 18:18

题目描述

小B有n个下属,现小B要带着一些下属让别人拍照。

有m个人,每个人都愿意付给小B一定钱让n个人中的一些人进行合影。如果这一些人没带齐那么就不能拍照,小B也不会得到钱。

注意:带下属不是白带的!!!对于每个下属,如果他带了那么小B需要给他一些钱,保证当他拍照时配合。

请问,小B的净收益最多是多少。

输入输出格式

输入格式:

第1行有2个正整数m和n(0<m,n<=100)。接下来的m行,每行是一个要求拍照的人的有关数据。第一个数是他同意支付该合影的费用;接着是该合影需要的若干下属的编号,以一个0作为行的结束标记。最后一行的n个数是带每个下属的费用。

输出格式:

一个数,表示最大收益。小B可以一个人也不带。

输入输出样例

输入样例#1: 
2 310 1 2 025 2 3 05 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 999999999using 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;}

原创粉丝点击