zoukankan      html  css  js  c++  java
  • 志愿者招募 [NOI2008] [鬼畜网络流]

    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

    【样例说明】
    招募3 名第一类志愿者和4 名第三类志愿者。 【数据规模和约定】
    30%的数据中,1 ≤ N, M ≤ 10,1 ≤ Ai ≤ 10;
    100%的数据中,1 ≤ N ≤ 1000,1 ≤ M ≤ 10000,题目中其他所涉及的数据均不超过2^31-1。

    Solution

    网络流的难点在于建模,此题的建模方法很鬼畜。

    首先明确,这显然是一个最小费用最大流的题。

    有一个源点S,汇点T,中间夹了n+1个点(对,就是n+1)

    α)首先,S->1和n+1->T分别连一条(INF,0)的边             ((x,y)表示容量x,代价y)

    β)然后对于i->i+1,连一条边为(INF-Ai,0)    

    (γ)在最后每一类志愿者,连一条Si->Ti+1(INF,Ci)的边

    为什么要这样做?

    我们一开始建的两条边(α)确保了到最后一定流量为INF (最大流特性)

    然后再看剩下的边,会优先走(β),因为代价是0

    但是由于减掉了Ai,意味着要保证满流必须走有代价的边(γ)

    最后的答案就是(每次流量×代价和)的和了

    Code

     1 #include<queue>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<iostream>
     5 #include<algorithm>
     6 #define RG register int
     7 #define rep(i,a,b)    for(RG i=a;i<=b;i++)
     8 #define per(i,a,b)    for(RG i=a;i>=b;i--)
     9 #define inf (1<<30)
    10 #define maxn 1005
    11 #define maxm 1000005
    12 using namespace std;
    13 int n,m,cnt=1,S,T;
    14 int ned[maxn],head[maxn],dis[maxn],vis[maxn],pre[maxn];
    15 struct E{
    16     int u,v,fl,cost,next;
    17 }e[maxm<<2];
    18 inline int read()
    19 {
    20     int x=0,f=1;char c=getchar();
    21     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    22     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    23     return x*f;
    24 }
    25 
    26 inline void add(int u,int v,int fl,int cost)
    27 {
    28     e[++cnt]=(E){u,v,fl,cost,head[u]},head[u]=cnt,swap(u,v);
    29     e[++cnt]=(E){u,v,0,-cost,head[u]},head[u]=cnt;
    30 }
    31 
    32 int SPFA()
    33 {
    34     queue<int> que;
    35     memset(dis,63,sizeof(dis)),memset(pre,-1,sizeof(pre)),memset(vis,0,sizeof(vis));
    36     que.push(S),dis[S]=0;
    37     RG u,v;
    38     while(!que.empty())
    39     {
    40         u=que.front(),que.pop();vis[u]=0;
    41         for(RG i=head[u];i;i=e[i].next)
    42         {
    43             v=e[i].v;
    44             if(e[i].fl>0&&dis[v]>dis[u]+e[i].cost)
    45             {
    46                 pre[v]=i;
    47                 dis[v]=dis[u]+e[i].cost;
    48                 if(!vis[v])
    49                     vis[v]=1,que.push(v);
    50             }
    51         }
    52     }
    53     return pre[T]!=-1;
    54 }
    55 
    56 void MCMF()
    57 {
    58     int ans=0;
    59     while(SPFA())
    60     {
    61         RG now=T,fl=inf;
    62         while(now!=S)    fl=min(fl,e[pre[now]].fl),now=e[pre[now]].u;
    63         ans+=dis[T]*fl;
    64         now=T;
    65         while(now!=S)    e[pre[now]].fl-=fl,e[pre[now]^1].fl+=fl,now=e[pre[now]].u;    //bug    
    66     }
    67     printf("%d",ans);
    68 }
    69 
    70 int main()
    71 {
    72     n=read(),m=read(),S=0,T=n+2;
    73     for(RG i=1,tmp;i<=n;i++)
    74         tmp=read(),add(i,i+1,inf-tmp,0);    
    75     for(RG i=1,u,v,val;i<=m;i++)
    76         u=read(),v=read(),val=read(),add(u,v+1,inf,val);
    77     add(S,1,inf,0),add(n+1,T,inf,0);
    78     MCMF();
    79     return 0;
    80 }
    View Code
  • 相关阅读:
    Html.RenderPartial和Html.Partial区别
    SQL Server事务处理
    为什么要使用消息队列(一)
    消息队列的优缺点(三)
    消息队列消息顺序性
    分布式事务之消息队列解决方案
    Solr与tomcat整合,并添加中文分词器
    Solr设置高亮
    Solr执行查询操作
    Lucene使用Filter搜索过滤
  • 原文地址:https://www.cnblogs.com/ibilllee/p/8747632.html
Copyright © 2011-2022 走看看