zoukankan      html  css  js  c++  java
  • [NOI2008] [bzoj1061] 志愿者招募

      还是一道费用流的题目。话不多说,进入正题。

      题意:给定n个点和m种从l到r覆盖一层的费用,求满足所有点的覆盖层数都大等于权值的最小费用

      分析:要做到区间修改,看似比较麻烦。

         用差分把区间修改变成单点修改(左端+,右端-)

         那么建一种边,从右端+1的位置流向左端点的位置,花费为c

         然后有可能覆盖层数过大,我们建一种边使满足单点层数-1花费为0,使最后的覆盖结果一定是与要求的一致

         最后就是建源到某个点的流量剩余(或这个点到汇的流量需求)

      下面贴上代码:

    #include<cstdio>
    using namespace std;
    const int inf=2147483647;
    int n,m;
    int tot=1,mx,q[1010],d[1010],pree[1010],h[1010];
    struct edge{int to,nxt,cst,cap;}e[30010];
    bool vis[1010];
    int mn(int x,int y){return x>y?y:x;}
    void add(int fr,int to,int cst,int cap)
    {
        e[++tot]={to,h[fr],cst,cap};h[fr]=tot;
        e[++tot]={fr,h[to],-cst,0};h[to]=tot;
    }
    void init()
    {
        scanf("%d%d",&n,&m);
        int now,lst=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&now);
            int cst=now-lst;lst=now;
            if(cst>0)add(i,n+2,0,cst),mx+=cst;//差分建图 
            else add(0,i,0,-cst);
            add(i,i+1,0,inf);//单点减1答案不变 
        }
        add(0,n+1,0,lst);
        for(int i=1;i<=m;i++)
        {
            int l,r,c;
            scanf("%d%d%d",&l,&r,&c);
            add(r+1,l,c,inf);//区间加法头加尾减 
        }
        n+=2; 
    }
    bool spfa()
    {
        for(int i=1;i<=n;i++)d[i]=inf;
        int l=0,r=1;q[1]=0;vis[0]=1;
        while(l!=r)
        {
            int x=q[l=l==n?0:l+1];
            for(int i=h[x];i;i=e[i].nxt)
                if(e[i].cap&&e[i].cst+d[x]<d[e[i].to])
                {
                    int v=e[i].to;
                    pree[v]=i;
                    d[v]=d[x]+e[i].cst;
                    if(!vis[v])
                    {
                        if(d[v]>d[l+1])q[r=r==n?0:r+1]=v;
                        else q[l]=v,l=l==0?n:l-1;
                        vis[v]=1;
                    }
                }
            vis[x]=0;
        }
        return d[n]==inf?0:1;
    }
    int costflow()
    {
        int cost=0,mm=0;
        while(spfa())
        {
            int mi=inf;
            for(int i=n;i;i=e[pree[i]^1].to)
                mi=mn(mi,e[pree[i]].cap);
            for(int i=n;i;i=e[pree[i]^1].to)
            {
                int ee=pree[i];
                e[ee].cap-=mi;
                e[ee^1].cap+=mi;
            }
            cost+=d[n]*mi;
            mm+=mi;
        }
        return mm==mx?cost:0;
    }
    int main()
    {
        init();
        printf("%d",costflow());
        return 0;
    }
    本文由qrc出品,若不在本博客上看到,请与本人联系。 网址:http://www.cnblogs.com/qrcer
  • 相关阅读:
    Construct Binary Tree from Preorder and Inorder Traversal
    Construct Binary Tree from Inorder and Postorder Traversal
    Maximum Depth of Binary Tree
    Sharepoint 2013 创建TimeJob 自动发送邮件
    IE8 不能够在Sharepoint平台上在线打开Office文档解决方案
    TFS安装与管理
    局域网通过IP查看对方计算机名,通过计算机名查看对方IP以及查看在线所有电脑IP
    JS 隐藏Sharepoint中List Item View页面的某一个字段
    SharePoint Calculated Column Formulas & Functions
    JS 两个一组数组转二维数组
  • 原文地址:https://www.cnblogs.com/qrcer/p/6597241.html
Copyright © 2011-2022 走看看