[Bzoj1061][Noi2008]志愿者招募(费用流)

题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1061

一开始疯狂想dp,然后队友走过来瞄一眼就告诉我像费用流,菜的真实,jpg。

一种比较经典的建图方法:

源点连第一天,流量inf,费用0。

第n天连汇点,流量inf,费用0。

第i天连第i+1天,流量inf-a[i](需要的人数),费用0。(限制流量)

第i种可以选择的人,将Si+1天连Ti天,流量inf,费用Ci。(花钱购买流量)

菜的真实.jpg

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int maxn = 2e6 + 10;
 5 const int inf = 1e7 + 10;
 6 struct node {
 7     int s, e, w, cost, next;
 8 }edge[maxn];
 9 int head[maxn], len;
10 void init() {
11     memset(head, -1, sizeof(head));
12     len = 0;
13 }
14 void add(int s, int e, int w, int cost) {
15     edge[len].s = s;
16     edge[len].e = e;
17     edge[len].w = w;
18     edge[len].cost = cost;
19     edge[len].next = head[s];
20     head[s] = len++;
21 }
22 void insert(int s, int e, int w, int cost) {
23     add(s, e, w, cost);
24     add(e, s, 0, -cost);
25 }
26 int  pre[maxn], dis[maxn], vis[maxn];
27 bool spfa(int s, int e) {
28     memset(dis, 0x7f, sizeof(dis));
29     memset(vis, 0, sizeof(vis));
30     memset(pre, -1, sizeof(pre));
31     queue<int>q;
32     q.push(s);
33     vis[s] = 1, dis[s] = 0;
34     while (!q.empty()) {
35         int x = q.front();
36         q.pop();
37         vis[x] = 0;
38         for (int i = head[x]; i != -1; i = edge[i].next) {
39             int y = edge[i].e;
40             if (edge[i].w&&dis[y] > dis[x] + edge[i].cost) {
41                 dis[y] = dis[x] + edge[i].cost;
42                 pre[y] = i;
43                 if (vis[y] == 0) {
44                     vis[y] = 1;
45                     q.push(y);
46                 }
47             }
48         }
49     }
50     return pre[e] != -1;
51 }
52 int MCMF(int s, int e) {
53     int maxans = 0, minans = 0;
54     while (spfa(s, e)) {
55         int f = inf;
56         for (int i = pre[e]; i != -1; i = pre[edge[i].s])
57             f = min(f, edge[i].w);
58         maxans += f;
59         minans += dis[e] * f;
60         for (int i = pre[e]; i != -1; i = pre[edge[i].s]) {
61             edge[i].w -= f;
62             edge[i ^ 1].w += f;
63         }
64     }
65     return minans;
66 }
67 int main() {
68     int n, m;
69     int x, l, r, cost;
70     scanf("%d%d", &n, &m);
71     init();
72     int w = inf;
73     for (int i = 1; i <= n; i++) {
74         scanf("%d", &x);
75         add(i, i + 1, w - x, 0);
76         add(i + 1, i, 0, 0);
77     }
78     insert(0, 1, w, 0);
79     insert(n + 1, n + 2, w, 0);
80     for (int i = 1; i <= m; i++) {
81         scanf("%d%d%d", &l, &r, &cost);
82         insert(l, r + 1, w, cost);
83     }
84     printf("%d\n", MCMF(0, n + 2));
85     return 0;
86 }

 

posted @ 2019-07-02 09:04  祈梦生  阅读(314)  评论(0编辑  收藏  举报