bzoj1061 NOI2018 志愿者招募——solution

Description

 

  申奥成功后,布布经过不懈努力,终于成为奥组委下属公司人力资源部门的主管。布布刚上任就遇到了一个难
题:为即将启动的奥运新项目招募一批短期志愿者。经过估算,这个项目需要N 天才能完成,其中第i 天至少需要
Ai 个人。 布布通过了解得知,一共有M 类志愿者可以招募。其中第i 类可以从第Si 天工作到第Ti 天,招募费用
是每人Ci 元。新官上任三把火,为了出色地完成自己的工作,布布希望用尽量少的费用招募足够的志愿者,但这
并不是他的特长!于是布布找到了你,希望你帮他设计一种最优的招募方案。

Input

  第一行包含两个整数N, M,表示完成项目的天数和可以招募的志愿者的种类。 接下来的一行中包含N 个非负
整数,表示每天至少需要的志愿者人数。 接下来的M 行中每行包含三个整数Si, Ti, Ci,含义如上文所述。为了
方便起见,我们可以认为每类志愿者的数量都是无限多的。

Output

  仅包含一个整数,表示你所设计的最优方案的总费用。

        -bybzoj

http://www.lydsy.com/JudgeOnline/problem.php?id=1061



介绍一种简单的有上下界费用流解法:

 

把每个志愿者看做1流量,
首先把n天按从1到n的顺序顺次连INF的边,任何刑期未满的志愿者都可以在这个边上流动;
由于每天有一个人数下限,于是考虑,拆点,在代表同一天的两点见连一条有下界的边,
如何把志愿者引入这个图?
考虑每个志愿者依照自己所属的种类,将在固定的点进入图,固定的点离开图,并在这两点间流动,
于是若类型i的志愿者从ai入,bi出,
则若只有i的话,ai有多少流量被引入,bi就有多少流量消失,不妨连一条费用1流量INF的边从bi到ai
至此网络流图模型便建好了
在此图上跑有上下界的最小费用流即可;
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
int n,m,S,T,ansf,answ;
struct ss{
    int next,to,f,v,cp;
}e[28010];
int first[2010],num;
int que[100010],vis[2010],flow[2010],way[2010],dis[2010],pre[2010];
void bui_(int ,int ,int ,int );
void build(int ,int ,int ,int );
bool spfa();
void EK();
int main(){
    int i,j,k,l;
    scanf("%d%d",&n,&m);
    S=(n<<1)+1,T=S+1;
    for(i=1;i<=n;i++){
        bui_(i,i+n,INF,0);
        scanf("%d",&j);
        if(j)bui_(S,i+n,j,0),bui_(i,T,j,0);
        if(i!=n)
            bui_(i+n,i+1,INF,0);
    }
    for(i=1;i<=m;i++){
        scanf("%d%d%d",&j,&k,&l);
        bui_(k+n,j,INF,l);
    }
    while(spfa())
        EK();
    printf("%d\n",ansf);
}
void bui_(int f,int t,int fi,int vi){
    build(f,t,fi,vi),e[num].cp=num+1;
    build(t,f,0,-vi),e[num].cp=num-1;
}
void build(int f,int t,int fi,int vi){
    e[++num].next=first[f];
    e[num].to=t,e[num].f=fi,e[num].v=vi;
    first[f]=num;
}
bool spfa(){
    int i,h=0,t=1;
    memset(dis,0x3f,sizeof(dis));
    que[t]=S,vis[S]=1,dis[S]=0,flow[S]=INF;
    while(h<t){
        vis[que[++h]]=0;
        for(i=first[que[h]];i;i=e[i].next)
            if(e[i].f&&dis[e[i].to]>dis[que[h]]+e[i].v){
                dis[e[i].to]=dis[que[h]]+e[i].v;
                way[e[i].to]=i,pre[e[i].to]=que[h];
                flow[e[i].to]=min(flow[que[h]],e[i].f);
                if(!vis[e[i].to]){
                    que[++t]=e[i].to;
                    vis[que[t]]=1;
                }
            }
    }
    return dis[T]!=INF;
}
void EK(){
    int i;
    ansf+=flow[T]*dis[T];
    answ+=flow[T];
    for(i=T;i;i=pre[i])
        if(way[i])
            e[way[i]].f-=flow[T],e[e[way[i]].cp].f+=flow[T];
}

 

posted @ 2018-01-05 16:17  F.W.Nietzsche  阅读(230)  评论(0编辑  收藏  举报