[最小割] Bzoj P1391 order
Description
有N个工作,M种机器,每种机器你可以租或者买过来. 每个工作包括若干道工序,每道工序需要某种机器来完成,你可以通过购买或租用机器来完成。 现在给出这些参数,求最大利润
Input
第一行给出 N,M(1<=N<=1200,1<=M<=1200) 下面将有N块数据,每块数据第一行给出完成这个任务能赚到的钱(其在[1,5000])及有多少道工序 接下来若干行每行两个数,分别描述完成工序所需要的机器编号及租用它的费用(其在[1,20000]) 最后M行,每行给出购买机器的费用(其在[1,20000])
Output
最大利润
Sample Input
2 3
100 2
1 30
2 20
100 2
1 40
3 80
50
80
110
100 2
1 30
2 20
100 2
1 40
3 80
50
80
110
Sample Output
50
HINT
题解
- 如果一台机器只能买的话,就是一个经典的最大权闭合子图问题
- s到每台机器连流量为花费的边,每台机器到依赖它的项目连流量为inf的边,每个项目到t连流量为收益的边
- 所有项目收益总和-最小割就是答案
- 那如果机器可以租呢? 只要把机器连向项目的边的流量改为租机器的流量就好了
- 注意,要当前弧优化
代码
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 #include <algorithm> 5 #define inf 1000000000 6 using namespace std; 7 int ans,tot,n,m,T,cnt=1,Q[30005],head[30005],state[30005],cur[30005]; 8 struct edge{ int to,from,v; }e[3000005]; 9 void insert(int x,int y,int v) 10 { 11 e[++cnt].to=y,e[cnt].from=head[x],head[x]=cnt,e[cnt].v=v; 12 e[++cnt].to=x,e[cnt].from=head[y],head[y]=cnt,e[cnt].v=0; 13 } 14 bool bfs() 15 { 16 int p=0,q=1; 17 memset(state,-1,sizeof(state)); 18 state[0]=Q[0]=0; 19 while (p!=q) 20 { 21 int u=Q[p]; p++; if (p==2501) p=0; 22 for (int i=head[u];i;i=e[i].from) if (e[i].v&&state[e[i].to]==-1) state[e[i].to]=state[u]+1,Q[q++]=e[i].to,q=(q==2501)?0:q; 23 } 24 return state[T]!=-1; 25 } 26 int dfs(int x,int maxf) 27 { 28 if (x==T) return maxf; 29 int f=0,r; 30 for (int i=cur[x];i;i=e[i].from) 31 if (e[i].v&&state[e[i].to]==state[x]+1) 32 { 33 r=dfs(e[i].to,min(e[i].v,maxf-f)),e[i].v-=r,e[i^1].v+=r,f+=r; 34 if (e[i].v>0) cur[x]=i; 35 if (f==maxf) return f; 36 } 37 if (!f) state[x]=-1; 38 return f; 39 } 40 void dinic() { while (bfs()) for (int i=0;i<=T;i++) cur[i]=head[i],ans-=dfs(0,inf); } 41 int main() 42 { 43 scanf("%d%d",&n,&m),T=n+m+1; 44 for (int i=1,x,y;i<=n;i++) 45 { 46 scanf("%d%d",&x,&y),insert(0,i,x),ans+=x; 47 for (int j=1,l,r;j<=y;j++) scanf("%d%d",&l,&r),insert(i,n+l,r); 48 } 49 for (int i=1,x;i<=m;i++) scanf("%d",&x),insert(n+i,T,x); 50 dinic(); 51 printf("%d",ans); 52 }