zoukankan      html  css  js  c++  java
  • 【BZOJ1391】Order(CEOI2008)-最小割

    测试地址:Order
    题目大意:N项任务和M种机器,每项任务都有若干道工序,每道工序需要使用一种机器,完成第i项任务的所有工序就能拿到Ci的报酬。对于机器可以租用或者购买,租用时只能用于某一项任务的某一道工序,用于不同位置时租金可能不同。而购买是一次性的,只要买下来,所有用到这台机器加工的工序都能做,而只需付一次的钱。现在给你这些信息,问能得到的最大利润是多少。1N,M1200
    做法:本题需要用到最小割。
    我们发现直接求最大利润比较困难,所以我们把所有任务的报酬之和看做预期的利润,求最小的损失,也就是成本。
    我们知道,损失会产生于三个方面:一是某项任务无法完成,二是在某道工序租用某种机器,三是购买某种机器。于是我们建图,从源点到每项任务连一条容量为报酬的边,从每种机器到汇点连一条容量为价钱的边,从每项任务到各工序所需的机器连一条容量为租金的边。因为我们知道,如果要完成一项任务,我们必须租用或者购买它所需的全部机器,这就等价于从这项任务到汇点不存在路径,否则我们就完不成这项任务,等价于割掉源点到这项任务的边。因此我们意识到要求一个最小割,我们就完成了这一题。注意要加当前弧优化,不然会TLE。
    这个东西很像最大权闭合子图的模型,只不过有了租金这一概念,所以原图中的边容量不应为正无穷。
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int inf=1000000000;
    int n,m,sum=0,S,T;
    int first[3010]={0},tot=1,cur[3010],lvl[3010];
    int h,t,q[3010];
    struct edge
    {
        int v,next,f;
    }e[3000010];
    
    void insert(int a,int b,int f)
    {
        e[++tot].v=b,e[tot].next=first[a],e[tot].f=f,first[a]=tot;
        e[++tot].v=a,e[tot].next=first[b],e[tot].f=0,first[b]=tot;
    }
    
    void init()
    {
        scanf("%d%d",&n,&m);
        S=n+m+1,T=n+m+2;
        for(int i=1;i<=n;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            sum+=x;
            insert(S,i,x);
            for(int j=1;j<=y;j++)
            {
                int a,b;
                scanf("%d%d",&a,&b);
                insert(i,n+a,b);
            }
        }
        for(int i=1;i<=m;i++)
        {
            int x;
            scanf("%d",&x);
            insert(n+i,T,x);
        }
    }
    
    bool makelevel()
    {
        for(int i=1;i<=T;i++)
        {
            lvl[i]=-1;
            cur[i]=first[i];
        }
        lvl[S]=0;
        h=t=1;
        q[1]=S;
        while(h<=t)
        {
            int v=q[h++];
            for(int i=first[v];i;i=e[i].next)
                if (e[i].f&&lvl[e[i].v]==-1)
                {
                    lvl[e[i].v]=lvl[v]+1;
                    q[++t]=e[i].v;
                }
        }
        return lvl[T]!=-1;
    }
    
    int maxflow(int v,int maxf)
    {
        if (v==T) return maxf;
        int ret=0,f;
        for(int i=cur[v];i;i=e[i].next)
        {
            if (e[i].f&&lvl[e[i].v]==lvl[v]+1)
            {
                f=maxflow(e[i].v,min(maxf-ret,e[i].f));
                ret+=f;
                e[i].f-=f;
                e[i^1].f+=f;
                if (ret==maxf) break;
            }
            cur[v]=i;
        }
        if (!ret) lvl[v]=-1;
        return ret;
    }
    
    void dinic()
    {
        int maxf=0;
        while(makelevel()) maxf+=maxflow(S,inf);
        printf("%d",sum-maxf);
    }
    
    int main()
    {
        init();
        dinic();
    
        return 0;
    }
  • 相关阅读:
    HTML学习笔记
    JSP与Servlet的跳转及得到路径方法整理(转)
    Servlet 学习笔记6:Cookie
    工作=娱乐=爱[龙]
    幸福的方法[龙]
    10张海报,激励人生[龙]
    8个方法让你安然度过低效率的日子[龙]
    使用空余时间的20个有效途径
    人生三点钟
    2013计划
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793446.html
Copyright © 2011-2022 走看看