【CEOI2008】bzoj1391 order

177 篇文章 0 订阅

Description 有N个工作,M种机器,每种机器你可以租或者买过来.
每个工作包括若干道工序,每道工序需要某种机器来完成,你可以通过购买或租用机器来完成。 现在给出这些参数,求最大利润 Input 第一行给出
N,M(1<=N<=1200,1<=M<=1200)
下面将有N块数据,每块数据第一行给出完成这个任务能赚到的钱(其在[1,5000])及有多少道工序
接下来若干行每行两个数,分别描述完成工序所需要的机器编号及租用它的费用(其在[1,20000])
最后M行,每行给出购买机器的费用(其在[1,20000]) Output 最大利润

裸的最大权闭合子图需要在收益和要求间连正无穷的边,代表不能割断。只需要改成租用的花费即可。
dinic需要当前弧优化。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int s=10005,t=10006,oo=0x3f3f3f3f;
int fir[10010],ne[4000010],to[4000010],w[4000010],
f[10010],que[10010],cur[10010],
n,m,num;
int rd()
{
    int x=0;
    char c=getchar();
    while (c<'0'||c>'9') c=getchar();
    while (c>='0'&&c<='9')
    {
        x=x*10+c-'0';
        c=getchar();
    }
    return x;
}
void add(int u,int v,int x)
{
    num++;
    ne[num*2]=fir[u];
    fir[u]=num*2;
    to[num*2]=v;
    w[num*2]=x;
    ne[num*2+1]=fir[v];
    fir[v]=num*2+1;
    to[num*2+1]=u;
    w[num*2+1]=0;
}
bool bfs()
{
    int u,v,hd=1,tl=1;
    for (int i=1;i<=n+m;i++) f[i]=0;
    f[t]=0;
    f[s]=1;
    que[1]=s;
    while (hd<=tl)
    {
        u=que[hd++];
        for (int i=fir[u];i;i=ne[i])
            if (!f[v=to[i]]&&w[i])
            {
                f[v]=f[u]+1;
                que[++tl]=v;
            }
    }
    for (int i=1;i<=m+n;i++) cur[i]=fir[i];
    cur[s]=fir[s];
    cur[t]=fir[t];
    return f[t];
}
int dfs(int u,int lim)
{
    int v,x,ret=0;
    if (u==t) return lim;
    for (int i=cur[u];i&&ret<lim;i=ne[i])
        if (f[v=to[i]]==f[u]+1&&w[i])
        {
            x=dfs(v,min(lim-ret,w[i]));
            ret+=x;
            w[i]-=x;
            if (w[i]) cur[u]=i;
            w[i^1]+=x;
        }
    if (!ret) f[u]=0;
    return ret;
}
int main()
{
    int ans=0,x,y,z,u;
    n=rd();
    m=rd();
    for (int i=1;i<=n;i++)
    {
        x=rd();
        y=rd();
        ans+=x;
        add(s,i,x);
        while (y--)
        {
            u=rd();
            z=rd();
            add(i,u+n,z);
        }
    }
    for (int i=1;i<=m;i++)
        add(i+n,t,rd());
    while (bfs()) ans-=dfs(s,oo);
    printf("%d\n",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值