【bzoj1391】【Ceoi2008】【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

Sample Output

50

HINT

题解:源点向每个任务连收益的边,每个任务向它需要的机器连租费的边,每个机器向汇点连价格的边。

           用总收益减去最小割即可。

代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#define N 3000
#define M 1500000
#define INF 2100000000
using namespace std;
int point[N],next[M*2],n,m,cnt(1),k,a,b,c;
int dis[N],cur[N],gap[N],pre[N],s,T,sum,mn;
struct use{int st,en,v;}e[M*2];
bool f;
void add(int x,int y,int v){
  //cout<<x<<' '<<y<<' '<<v<<endl;
  next[++cnt]=point[x];point[x]=cnt;e[cnt].st=x;e[cnt].en=y;e[cnt].v=v;
  next[++cnt]=point[y];point[y]=cnt;e[cnt].st=y;e[cnt].en=x;e[cnt].v=0;
}
int isap(){
  int u(1),i,ans(0);gap[0]=T;
  for (i=1;i<=T;i++) cur[i]=point[i];
  while(dis[1]<T){
    f=false;
    for (i=cur[u];i;i=next[i])
	 if (e[i].v&&dis[e[i].en]+1==dis[u]){f=true;cur[u]=i;break;}
	if (f){
	  u=e[i].en;pre[u]=i;
	  if (u==T){
	    mn=INF;
	    for (i=T;i!=1;i=e[pre[i]].st) mn=min(mn,e[pre[i]].v);
	    ans+=mn;
	    for (i=T;i!=1;i=e[pre[i]].st) e[pre[i]].v-=mn,e[pre[i]^1].v+=mn;
	    u=1;
	  }
	}
	else{
	  gap[dis[u]]--;if (!gap[dis[u]]) return ans;
	  for (mn=T+1,i=point[u];i;i=next[i]) if (e[i].v)mn=min(mn,dis[e[i].en]);
	  dis[u]=mn+1;gap[dis[u]]++;cur[u]=point[u];if (u!=1)u=e[pre[u]].st;
	} 
  }
  return ans;
}
int main(){
  scanf("%d%d",&n,&m);T=n+m+2;
  for (int i=1;i<=n;i++){
    scanf("%d%d",&a,&s);
	add(1,i+1,a);sum+=a;
	for (int j=1;j<=s;j++){scanf("%d%d",&k,&c);add(i+1,k+n+1,c);} 	
  }	
  for (int i=1;i<=m;i++){scanf("%d",&c);add(i+n+1,T,c);}
  printf("%d\n",sum-isap());
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值