zoukankan      html  css  js  c++  java
  • [bzoj1061]志愿者招募

    将问题反过来考虑,即最多选择多少人(流量最大)使得答案最少(费用最少),很明显是一个费用流的模型
    用一条流表示每一天的人数都+1,可以发现即按如下方式建图:1.对于每一种志愿者,li向ri+1连(+oo,ci)的边;2.对于每一天,向前一天连(+oo,0)的边,表示可以多次覆盖;3.源点向1连一条max(ai)的边
    但这样会导致答案过大,因为实际上并不需要每一天都被覆盖max(ai)次
    仍然反过来考虑,可以理解为我可以不被覆盖max(ai)-ai次,因此i向i+1连一条max(ai)-ai的边即可

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 1005
     4 #define ll long long
     5 struct ji{
     6     int nex,to,cost;
     7     ll len; 
     8 }edge[N*30];
     9 queue<int>q;
    10 int E,n,m,x,y,z,head[N],a[N],vis[N],from[N];
    11 ll d[N];
    12 void add(int x,int y,ll z,int w){
    13     edge[E].nex=head[x];
    14     edge[E].to=y;
    15     edge[E].len=z;
    16     edge[E].cost=w;
    17     head[x]=E++;
    18     if (E&1)add(y,x,0,-w);
    19 }
    20 bool spfa(){
    21     memset(d,0x3f,sizeof(d));
    22     memset(vis,0,sizeof(vis));
    23     q.push(0);
    24     d[0]=0;
    25     while (!q.empty()){
    26         int k=q.front();
    27         q.pop();
    28         vis[k]=0;
    29         for(int i=head[k];i!=-1;i=edge[i].nex){
    30             int v=edge[i].to;
    31             if ((edge[i].len)&&(d[v]>d[k]+edge[i].cost)){
    32                 d[v]=d[k]+edge[i].cost;
    33                 from[v]=i;
    34                 if (!vis[v]){
    35                     vis[v]=1;
    36                     q.push(v);
    37                 }
    38             }
    39         }
    40     }
    41     return d[n+1]!=d[n+2];
    42 }
    43 int main(){
    44     scanf("%d%d",&n,&m);
    45     ll s=0,ans=0;
    46     memset(head,-1,sizeof(head));
    47     for(int i=1;i<=n;i++){
    48         scanf("%d",&a[i]);
    49         s+=a[i];
    50     }
    51     add(0,1,s,0);
    52     for(int i=1;i<=n;i++)add(i,i+1,s-a[i],0);
    53     for(int i=1;i<=m;i++){
    54         scanf("%d%d%d",&x,&y,&z);
    55         add(x,y+1,s,z);
    56     }
    57     while (spfa()){
    58         s=1e18;
    59         for(int i=n+1;i;i=edge[from[i]^1].to)s=min(s,edge[from[i]].len);
    60         ans+=s*d[n+1];
    61         for(int i=n+1;i;i=edge[from[i]^1].to){
    62             edge[from[i]].len-=s;
    63             edge[from[i]^1].len+=s;
    64         }
    65     }
    66     printf("%lld",ans);
    67 }
    View Code
  • 相关阅读:
    hdu 1695(莫比乌斯反演)
    hdu 6035(Colorful Tree)
    Splay模板(序列终结者)
    我的CSDN博客
    【洛谷P2041 分裂游戏】数学+瞎蒙
    【洛谷P1962 斐波那契数列】矩阵快速幂+数学推导
    【LOJ 109 并查集】 并查集
    【洛谷P1816 忠诚】线段树
    【洛谷1339 [USACO09OCT]】热浪Heat Wave 图论+最短路
    【洛谷1433】吃奶酪 搜索+剪枝
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/11790233.html
Copyright © 2011-2022 走看看