• bzoj 1061 志愿者招募 有上下界费用流做法


          把每一天看作一个点,每一天的志愿者数目就是流量限制,从i到i+1连边,上下界就是(A[i],+inf)。

          对于每一类志愿者,从T[i]+1到S[i]连边,费用为招募一个志愿者的费用,流量为inf。这样每多1的流量,就多了一个从S[i]到T[i]+1的循环流。

          求一遍无源汇的最小费用可行流就可以了。

          

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cstring>
     5 #include<queue>
     6 #define inf 0x3f3f3f3f
     7 #define N 100005
     8 using namespace std;
     9 int n,m;
    10 int v[N];
    11 int head[N],ver[N],nxt[N],tot,f[N],quan[N];
    12 void add(int a,int b,int c,int d)
    13 {
    14     tot++;nxt[tot]=head[a];head[a]=tot;ver[tot]=b;quan[tot]=d;f[tot]=c;
    15     tot++;nxt[tot]=head[b];head[b]=tot;ver[tot]=a;quan[tot]=-d;f[tot]=0;
    16     return ;
    17 }
    18 int S,T;
    19 int dis[2005],in[2005],with[2005],mn[2005];
    20 bool tell()
    21 {
    22     memset(dis,0x3f,sizeof(dis));
    23     memset(in,0,sizeof(in));
    24     dis[S]=0;mn[S]=inf;
    25     queue<int>q;
    26     q.push(S);
    27     while(!q.empty())
    28     {
    29         int tmp=q.front();q.pop();in[tmp]=0;
    30         for(int i=head[tmp];i;i=nxt[i])
    31         {
    32             if(dis[ver[i]]>dis[tmp]+quan[i]&&f[i])
    33             {
    34                 dis[ver[i]]=dis[tmp]+quan[i];
    35                 with[ver[i]]=i;mn[ver[i]]=min(f[i],mn[tmp]);
    36                 if(!in[ver[i]])in[ver[i]]=1,q.push(ver[i]);
    37             }
    38         }
    39     }
    40     return dis[T]!=inf;
    41 }
    42 int zeng()
    43 {
    44     for(int i=T;i;i=ver[with[i]^1])
    45     {
    46         f[with[i]]-=mn[T];f[with[i]^1]+=mn[T];
    47     }
    48     return mn[T]*dis[T];
    49 }
    50 int main()
    51 {
    52    scanf("%d%d",&n,&m);
    53    S=0;T=n+2;
    54    tot=1;
    55    int tmp;
    56    for(int i=1;i<=n;i++)
    57    {
    58            scanf("%d",&tmp);
    59            add(i,T,tmp,0);
    60         add(S,i+1,tmp,0);
    61         add(i,i+1,inf,0);
    62    }
    63    int t1,t2,t3;
    64    for(int i=1;i<=m;i++)
    65    {
    66          scanf("%d%d%d",&t1,&t2,&t3);
    67          add(t2+1,t1,inf,t3);
    68    }
    69    int ans=0;
    70    while(tell())ans+=zeng();
    71    printf("%d
    ",ans);
    72    return 0;
    73 }

          

  • 相关阅读:
    [JLOI2015] 管道连接
    【知识点】斯坦纳树
    [ZJOI2010] 网络扩容
    【知识点】网络流常见模型
    [NOI2009] 植物大战僵尸
    [NOI2007] 货币兑换
    【知识点】分治相关算法
    [NOI2005] 月下柠檬树
    [HNOI2012] 射箭
    [SDOI2014] 向量集
  • 原文地址:https://www.cnblogs.com/ezyzy/p/6209869.html
Copyright © 2020-2023  润新知