[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;
}

 

posted @ 2017-03-21 22:39  qrc  阅读(214)  评论(0编辑  收藏  举报