题目描述
小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;
然后跑最大流,总流量就是最优方案的总花费;
然后,总收益=总价值-总花费。
代码实现:
1 #include<cstdio> 2 #include<cstring> 3 #define inf 1000000 4 #define maxn 300 5 #define maxm 300000 6 int n,m,s,t,tw,tot; 7 int a,b,c; 8 int d[maxn],q[maxn],head,tail; 9 int h[maxn],hs=1; 10 struct edge{int s,n,w;}e[maxm]; 11 inline int min(int x,int y){return x<y?x:y;} 12 void add(int q,int z,int w){ 13 e[++hs]=(edge){z,h[q],w},h[q]=hs; 14 e[++hs]=(edge){q,h[z]},h[z]=hs; 15 } 16 void bfs(){ 17 memset(d,0,sizeof(d)); 18 head=tail=0; 19 q[head++]=s,d[s]=1; 20 while(head>tail){ 21 a=q[tail++]; 22 for(int i=h[a];i;i=e[i].n) 23 if(!d[e[i].s]&&e[i].w){ 24 d[e[i].s]=d[a]+1; 25 if(e[i].s==t) return; 26 q[head++]=e[i].s; 27 } 28 } 29 } 30 int ap(int k,int w){ 31 if(k==t) return w; 32 int uw=w; 33 for(int i=h[k];i&&uw;i=e[i].n) 34 if(e[i].w&&d[e[i].s]==d[k]+1){ 35 int nw=ap(e[i].s,min(uw,e[i].w)); 36 if(nw) e[i].w-=nw,e[i^1].w+=nw,uw-=nw; 37 else d[e[i].s]=0; 38 } 39 return w-uw; 40 } 41 void Dinic(){while(bfs(),d[t]) tw+=ap(s,inf);} 42 int main(){ 43 scanf("%d%d",&m,&n); 44 s=0,t=n+m+1; 45 for(int i=1;i<=m;i++){ 46 scanf("%d",&a); 47 tot+=a; 48 add(s,i,a); 49 while(scanf("%d",&a)&&a) add(i,a+m,inf); 50 } 51 for(int i=1;i<=n;i++) scanf("%d",&a),add(i+m,t,a); 52 Dinic(); 53 printf("%d ",tot-tw); 54 return 0; 55 }
因为hs初值忘了赋一,挣扎了1h,我绝对要玩。
本来想水水网络流,增加一下信心,没想到第一个题就坑了,搞了1h,才用土法子拿了80分。
明明不是正解,还固执己见,看了人家的AC代码,还不想该。
最后又惊扰了师傅他老人家,才知道是最大权闭合子图的裸题。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<cstring> 3 #define inf 100000000 4 #define maxn 300 5 #define maxm 300000 6 int n,m,s,t,tw; 7 int a,b,c; 8 int f[maxn],l[maxn],map[maxn][maxn]; 9 int d[maxn],q[maxn],head,tail; 10 int h[maxn],hs; 11 struct edge{int s,n,w;}e[maxm]; 12 inline int min(int x,int y){return x<y?x:y;} 13 void bfs(){ 14 memset(d,0,sizeof(d)); 15 head=tail=0; 16 q[head++]=s,d[s]=1; 17 while(head>tail){ 18 a=q[tail++]; 19 for(int i=h[a];i;i=e[i].n) 20 if(!d[e[i].s]&&e[i].w){ 21 d[e[i].s]=d[a]+1; 22 if(e[i].s==t) return; 23 q[head++]=e[i].s; 24 } 25 } 26 } 27 int ap(int k,int w){ 28 if(k==t) return w; 29 int uw=w; 30 for(int i=h[k];i&&uw;i=e[i].n) 31 if(e[i].w&&d[e[i].s]==d[k]+1){ 32 int nw=ap(e[i].s,min(uw,e[i].w)); 33 if(nw) e[i].w-=nw,e[i^1].w+=nw,uw-=nw; 34 else d[e[i].s]=0; 35 } 36 return w-uw; 37 } 38 bool Dinic(){ 39 bfs(); 40 if(!d[t]) return false; 41 tw+=ap(s,inf); 42 return true; 43 } 44 int main(){ 45 scanf("%d%d",&m,&n); 46 s=0,t=n+1; 47 for(int i=1;i<=m;i++){ 48 while(scanf("%d",&map[i][l[i]])&&map[i][l[i]++]); 49 map[i][l[i]-1]=t; 50 } 51 for(int i=1;i<=n;i++) scanf("%d",&f[i]); 52 for(int i=1;i<=m;i++){ 53 b=s; 54 for(int j=1;j<l[i]&&map[i][0];j++){ 55 a=b,b=map[i][j],c=map[i][0]; 56 e[++hs]=(edge){b,h[a],c},h[a]=hs; 57 e[++hs]=(edge){a,h[b]},h[b]=hs; 58 if(c>=f[b]) map[i][0]-=f[b],f[b]=0; 59 else f[b]-=c,map[i][0]=0; 60 } 61 } 62 while(Dinic()); 63 printf("%d ",tw); 64 return 0; 65 }
完成了可以看一下原版。
题目来源:洛谷