BZOJ 1061: [Noi2008]志愿者招募

1061: [Noi2008]志愿者招募

Time Limit: 20 Sec  Memory Limit: 162 MB
Submit: 4091  Solved: 2496
[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

 
[Submit][Status][Discuss]

 

无源汇最小费用可行流

 

原本无源汇的网络是这个样子的:

有$N+1$个点,代表每一天,其中有$N$条边连接,形如$<i,i+1,need_{i},inf,0>$,括号内分别为出点,入点,最小流量,最大流量,费用。这样就限制了每一天的志愿者人数最小值。

然后对于一类志愿者,如果设开始时间为$st$,终止时间为$ed$,费用为$ct$,那么连边$<ed+1,st,0,inf,ct>$,代表至少选0个这类志愿者(就是不选),至多inf(没有上限),选择一个费用为$ct$。

在这个网络上求解无源汇的最小费用可行流即可。

 

  1 #include <cstdio>
  2 #include <cstring>
  3 
  4 inline char Char(void)
  5 {
  6     static const short siz = 1024;
  7     
  8     static char buf[siz];
  9     static char *hd = buf + siz;
 10     static char *tl = buf + siz;
 11     
 12     if (hd == tl)
 13         fread(hd = buf, 1, siz, stdin);
 14     
 15     return *hd++;
 16 }
 17 
 18 inline int Int(void)
 19 {
 20     int ret = 0, neg = 0, c = Char();
 21     
 22     for (; c < 48; c = Char())
 23         if (c == '-')neg ^= true;
 24     
 25     for (; c > 47; c = Char())
 26         ret = ret * 10 + c - '0';
 27     
 28     return neg ? -ret : ret;
 29 }
 30 
 31 const int mxn = 2005;
 32 const int mxm = 20005;
 33 const int siz = 2000005;
 34 const int inf = 1000000007;
 35 
 36 int n, m, need[mxn], st[mxm], ed[mxm], ct[mxm], cnt[mxn];
 37 
 38 int s, t;
 39 int hd[siz];
 40 int to[siz];
 41 int fl[siz];
 42 int vl[siz];
 43 int nt[siz];
 44 
 45 inline void add(int u, int v, int f, int w)
 46 {
 47     static int tot = 0, init = 1;
 48     
 49     if (init)memset(hd, -1, sizeof(hd)), init = 0;
 50     
 51     nt[tot] = hd[u]; to[tot] = v; fl[tot] = f; vl[tot] = +w; hd[u] = tot++;
 52     nt[tot] = hd[v]; to[tot] = u; fl[tot] = 0; vl[tot] = -w; hd[v] = tot++;
 53 }
 54 
 55 int pre[mxn];
 56 int dis[mxn];
 57 
 58 inline bool spfa(void)
 59 {
 60     static int que[siz];
 61     static int inq[mxn];
 62     static int head, tail;
 63     
 64     for (int i = s; i <= t; ++i)dis[i] = inf;
 65     memset(inq, 0, sizeof(inq));
 66     head = 0, tail = 0;
 67     
 68     que[tail++] = s;
 69     pre[s] = -1;
 70     dis[s] = 0;
 71     
 72     while (head != tail)
 73     {
 74         int u = que[head++], v; inq[u] = 0;
 75         
 76         for (int i = hd[u]; ~i; i = nt[i])
 77             if (fl[i] && dis[v = to[i]] > dis[u] + vl[i])
 78             {
 79                 dis[v] = dis[u] + vl[i]; pre[v] = i ^ 1;
 80                 if (!inq[v])inq[que[tail++] = v] = 1;
 81             }
 82     }
 83     
 84     return dis[t] < inf;
 85 }
 86 
 87 inline int minCost(void)
 88 {
 89     int cost = 0;
 90     
 91     while (spfa())
 92     {
 93         int flow = inf;
 94         
 95         for (int i = pre[t]; ~i; i = pre[to[i]])
 96             if (flow > fl[i ^ 1])flow = fl[i ^ 1];
 97         
 98         for (int i = pre[t]; ~i; i = pre[to[i]])
 99             fl[i] += flow, fl[i ^ 1] -= flow;
100             
101         cost += flow * dis[t];
102     }
103     
104     return cost;
105 }
106 
107 signed main(void)
108 {
109     n = Int();
110     m = Int();
111     
112     for (int i = 1; i <= n; ++i)
113         need[i] = Int();
114     
115     for (int i = 1; i <= m; ++i)
116     {
117         st[i] = Int();
118         ed[i] = Int();
119         ct[i] = Int();
120     }
121     
122     s = 0, t = n + 2;
123     
124     for (int i = 1; i <= n; ++i)
125     {
126         add(i, i + 1, inf, 0);
127         
128         cnt[i] -= need[i];
129         cnt[i + 1] += need[i];
130     }
131     
132     for (int i = 1; i <= m; ++i)
133         add(ed[i] + 1, st[i], inf, ct[i]);
134     
135     for (int i = 1; i <= n + 1; ++i)
136         if (cnt[i] < 0)
137             add(i, t, -cnt[i], 0);
138         else if (cnt[i] > 0)
139             add(s, i, +cnt[i], 0);
140     
141     printf("%d\n", minCost());
142 }

 

@Author: YouSiki

 

posted @ 2017-01-12 07:59  YouSiki  阅读(172)  评论(0编辑  收藏  举报