• [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
  • 相关阅读:
    Linux ls
    Linux wc | 简单的字符数行数统计工具
    Linux less | 功能丰富的终端文本浏览器
    POSIX正则表达式 | BRE和ERE
    docker连不上私有仓库Harbor
    血泪史: k8s Initial timeout of 40s passed.
    无法访问k8s.gcr.io下载镜像问题解决办法
    Galera_Cluster_Mysql部署
    解决MobaXterm自动断开连接,亲测有效~
    Ubuntu使用dpkg查看与修改architecture的用法
  • 原文地址:https://www.cnblogs.com/qrcer/p/6597241.html
Copyright © 2020-2023  润新知