考虑最小割,即最少要去掉多少收益
先S向所有机器连边,流量为购买费用;所有机器向工作连边,流量为租借费用;工作向T连边,流量为收益
那么对于每一个工作,要么割掉连向T的边,要么购买/租借所有机器,同时由于购买了就一直可以用,所以购买费用直接连向S
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 3005 4 struct ji{ 5 int nex,to,len; 6 }edge[3000005]; 7 queue<int>q; 8 int E,n,m,x,y,z,ans,head[N],d[N],work[N]; 9 void add(int x,int y,int z){ 10 edge[E].nex=head[x]; 11 edge[E].to=y; 12 edge[E].len=z; 13 head[x]=E++; 14 if (E&1)add(y,x,0); 15 } 16 bool bfs(){ 17 while (!q.empty())q.pop(); 18 memset(d,-1,sizeof(d)); 19 q.push(0); 20 d[0]=0; 21 while (!q.empty()){ 22 int k=q.front(); 23 q.pop(); 24 for(int i=head[k];i!=-1;i=edge[i].nex) 25 if ((edge[i].len)&&(d[edge[i].to]<0)){ 26 d[edge[i].to]=d[k]+1; 27 q.push(edge[i].to); 28 if (edge[i].to>n+m)return 1; 29 } 30 } 31 return 0; 32 } 33 int dfs(int k,int s){ 34 if (k>n+m)return s; 35 for(int &i=work[k];i!=-1;i=edge[i].nex) 36 if ((edge[i].len)&&(d[edge[i].to]==d[k]+1)){ 37 int p=dfs(edge[i].to,min(s,edge[i].len)); 38 if (p){ 39 edge[i].len-=p; 40 edge[i^1].len+=p; 41 return p; 42 } 43 } 44 return 0; 45 } 46 int main(){ 47 scanf("%d%d",&n,&m); 48 memset(head,-1,sizeof(head)); 49 for(int i=1;i<=n;i++){ 50 scanf("%d%d",&x,&y); 51 ans+=x; 52 add(i+m,n+m+1,x); 53 for(int j=1;j<=y;j++){ 54 scanf("%d%d",&x,&z); 55 add(x,i+m,z); 56 } 57 } 58 for(int i=1;i<=m;i++){ 59 scanf("%d",&x); 60 add(0,i,x); 61 } 62 while (bfs()){ 63 memcpy(work,head,sizeof(head)); 64 while (x=dfs(0,0x3f3f3f3f))ans-=x; 65 } 66 printf("%d",ans); 67 }