hoj 2634 How to earn more

有m个项目和n个员工,做项目i可以获得Ai元,但是必须雇用若干指定的员工。雇用员工j需要Bj元,一旦雇用便可以参与多个项目。问最大收益。

1<=M,N<=100.

最小割。

源点向每个项目点连一条容量为项目获利的边。

每个项目点向本项目需要的所有员工点连一条容量为正无穷的边。

每个员工点向汇点连一条容量为雇用所需费用的边。

答案为所有项目获利和减最小割。

“蕴含式最大获利问题”,套用最大权闭合子图的建模即可。

割掉源点向项目点的边即为放弃此项目。

割掉员工点向汇点的边即为雇用此员工。

项目点和员工点间的边不可割去。

 1 #include<cstring>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<iostream>
 5 #include<queue>
 6 using namespace std;
 7 const int dian=210;
 8 const int bian=30005;
 9 const int INF=0x3f3f3f3f;
10 int ch[dian],h[dian],nxt[bian],ver[bian],val[bian],cr[dian];
11 int n,m,ans,aa,bb,tot;
12 int S,T;
13 void add(int a,int b,int c){
14     tot++;ver[tot]=b;nxt[tot]=h[a];val[tot]=c;h[a]=tot;
15     tot++;ver[tot]=a;nxt[tot]=h[b];val[tot]=0;h[b]=tot;
16 }
17 bool tell(){
18     memset(ch,-1,sizeof(ch));
19     queue<int>q;
20     q.push(S);
21     ch[S]=0;
22     while(!q.empty()){
23         int t=q.front();
24         q.pop();
25         for(int i=h[t];i;i=nxt[i])
26             if(ch[ver[i]]==-1&&val[i]){
27                 q.push(ver[i]);
28                 ch[ver[i]]=ch[t]+1;
29             }
30     }
31     return ch[T]!=-1;
32 }
33 int zeng(int a,int b){
34     if(a==T)
35         return b;
36     int r=0;
37     for(int i=cr[a];i&&b>r;i=nxt[i])
38         if(ch[ver[i]]==ch[a]+1&&val[i]){
39             int t=zeng(ver[i],min(b-r,val[i]));
40             val[i]-=t,r+=t,val[i^1]+=t;
41             if(val[i])
42                 cr[a]=i;
43         }
44     if(!r)
45         ch[a]=-1;
46     return r;
47 }
48 int dinic(){
49     int r=0,t;
50     while(tell()){
51         for(int i=1;i<=n+m+2;i++)
52             cr[i]=h[i];
53         while(t=zeng(S,INF))
54             r+=t;
55     }
56     return r;
57 }
58 int main(){
59     int cas;
60     scanf("%d",&cas);
61     while(cas--){
62         memset(nxt,0,sizeof(nxt));
63         memset(h,0,sizeof(h));
64         ans=0;
65         tot=1;
66         scanf("%d%d",&n,&m);
67         S=n+m+1;
68         T=n+m+2;
69         for(int i=1;i<=n;i++){
70             scanf("%d",&aa);
71             ans+=aa;
72             add(S,i,aa);
73         }
74         for(int i=1;i<=m;i++){
75             scanf("%d",&aa);
76             add(i+n,T,aa);
77         }
78         for(int i=1;i<=n;i++){
79             scanf("%d",&aa);
80             for(int j=1;j<=aa;j++){
81                 scanf("%d",&bb);
82                 add(i,bb+1+n,INF);
83             }
84         }
85         printf("%d\n",ans-dinic());
86     }
87     return 0;
88 }

 

posted @ 2016-12-26 08:52  dugudashen  阅读(335)  评论(0编辑  收藏  举报