• BZOJ 1061: [Noi2008]志愿者招募


    1061: [Noi2008]志愿者招募

    Time Limit: 20 Sec  Memory Limit: 162 MB
    Submit: 4064  Solved: 2476
    [Submit][Status][Discuss]

    Description

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

    Input

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

    Output

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

    Sample Input

    3 3
    2 3 4
    1 2 2
    2 3 5
    3 3 2

    Sample Output

    14

    HINT

    1 ≤ N ≤ 1000,1 ≤ M ≤ 10000,题目中其他所涉及的数据均 不超过2^31-1。

    Source

    分析:

    %LYD...

    这道题普遍做法貌似都是线性规划单纯形的做法,LYD告诉我们可以跑上下界最小费用可行流...

    我们把每一天看成一个点,然后从i向i+1连边,上界为inf,下界为ai,费用为0...

    然后对于每一类志愿者,从ti+1到si连边,上界为inf,下界为0,费用为ci...这样每花费ci的代价,就从si到ti增加一个流...

    然后就转化成了无源汇上下界最小费用可行流,其实就是把无源汇上下界可行流的最大流转化成最小费用最大流...

    怎么求无源汇上下界可行流?

    如果把C-B作为容量上界,0作为容量下界,就是一般的网络流模型。

    然而求出的实际流量为f(u,v)+B(u,v),不一定满足流量守恒,需要调整。

    设inB[u]=∑B(i,u),outB[u]=∑B(u,i),d[u]=inB[u]-outB[u]。

    新建源汇,S向d>0的点连边,d<0的点向汇点连边,容量为相应的d。 在该网络上求最大流,则每条边的流量+下界就是原网络的一个可行流。

    代码:

     1 #include<algorithm>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<cstdio>
     5 #include<queue>
     6 //by NeighThorn
     7 #define inf 0x3f3f3f3f
     8 #define INF 0x3f3f3f3f3f3f
     9 using namespace std;
    10 
    11 const int maxn=1000+5,maxm=100000+5;
    12 
    13 int n,m,S,T,cnt,w[maxm],hd[maxn],fl[maxm],to[maxm],nxt[maxm],Min[maxn],vis[maxn],from[maxn];
    14 
    15 long long dis[maxn],dif[maxn];
    16 
    17 inline bool spfa(void){
    18     for(int i=S;i<=T;i++)
    19         dis[i]=INF,Min[i]=inf;
    20     queue<int> q;q.push(S),vis[S]=1,dis[S]=0;
    21     while(!q.empty()){
    22         int top=q.front();q.pop();vis[top]=0;
    23         for(int i=hd[top];i!=-1;i=nxt[i])
    24             if(dis[to[i]]>dis[top]+w[i]&&fl[i]){
    25                 from[to[i]]=i;
    26                 dis[to[i]]=dis[top]+w[i];
    27                 Min[to[i]]=min(Min[top],fl[i]);
    28                 if(!vis[to[i]])
    29                     vis[to[i]]=1,q.push(to[i]);
    30             }
    31     }
    32     return dis[T]!=INF;
    33 }
    34 
    35 inline long long find(void){
    36     for(int i=T;i!=S;i=to[from[i]^1])
    37         fl[from[i]]-=Min[T],fl[from[i]^1]+=Min[T];
    38     return dis[T]*Min[T];
    39 }
    40 
    41 inline int dinic(void){
    42     int res=0;
    43     while(spfa())
    44         res+=find();
    45     return res;
    46 }
    47 
    48 inline void add(int l,int s,int x,int y){
    49     w[cnt]=l;fl[cnt]=s;to[cnt]=y;nxt[cnt]=hd[x];hd[x]=cnt++;
    50     w[cnt]=-l;fl[cnt]=0;to[cnt]=x;nxt[cnt]=hd[y];hd[y]=cnt++;
    51 }
    52 
    53 signed main(void){
    54     // freopen("in.txt","r",stdin);
    55     memset(hd,-1,sizeof(hd));
    56     scanf("%d%d",&n,&m);S=0,T=n+2;
    57     for(int i=1,y;i<=n;i++)
    58         scanf("%d",&y),add(0,inf,i,i+1),dif[i]-=y,dif[i+1]+=y;
    59     for(int i=1,s,x,y;i<=m;i++)
    60         scanf("%d%d%d",&x,&y,&s),add(s,inf,y+1,x);
    61     for(int i=1;i<=n+1;i++){
    62         if(dif[i]>0)
    63             add(0,dif[i],S,i);
    64         else if(dif[i]<0)
    65             add(0,-dif[i],i,T);
    66     }
    67     printf("%d
    ",dinic());
    68     return 0;   
    69 }
    View Code

    By NeighThorn

  • 相关阅读:
    Jenkins运行完Test后,把ngreport生成的测试报告 拷贝到相应的文件夹
    解析xml报classnotfound错误
    配置NGReport 报告中文
    fork()调用使子进程先于父进程被调度
    堆排序
    良序原理
    高速缓冲区初始化
    Python3:输出当前目录所有目录和文件--walk()函数
    Python3:输出当前目录所有文件的第二种方式-walk()函数
    Python3:递归实现输出目录下所有的文件
  • 原文地址:https://www.cnblogs.com/neighthorn/p/6255093.html
Copyright © 2020-2023  润新知