[NOI2008]志愿者招募
题面
分析
看到要求每天最少a[i]人 那么就反过来
使流量最大为inf - a[i]
因为是以天来限制人数 所以每天作为一条边
S --inf / 0 --> 第一天的起点 node[1]
最后一天终点 node[n + 1] -- inf / 0 --> T
第i天: node[i] -- inf / a[i] --> node[i + 1]
志愿者是补流 为了使最大流为inf
那么使node[s[i]] -- inf / c[i] --> node[t[i] + 1]
跑最小费用最大流即可
// luogu-judger-enable-o2
#include <bits/stdc++.h>
using namespace std;
/*
建图:S --inf / 0 --> 第一天的起点 node[1]
最后一天终点 node[n + 1] -- inf / 0 --> T
第i天: node[i] -- inf / a[i] --> node[i + 1]
志愿者是补流 为了使最大流为inf
那么使node[s[i]] -- inf / c[i] --> node[t[i] + 1]
*/
#define node(x, y) n + (x - 1) * ptot + (y)
typedef long long ll;
const ll inf = 1e11;
const int N = 1e3 + 5;
const int E = 1e6;
struct Edge{
int v, next; ll f, w;
}edge[E];
int esize = 1, head[N], S, T, n, m;
ll mxf, mc;
int fro, pre[N];
ll dis[N], fl[N], p[45];
queue<int> que;
inline void addedge(int x, int y, ll f, ll w){
edge[++esize] = (Edge){y, head[x], f, w}, head[x] = esize;
edge[++esize] = (Edge){x, head[y], 0, -w}, head[y] = esize;
//printf("%d %d %lld %lld\n", x, y, f, w);
}
inline bool spfa(){
for(int i = 1; i <= T; ++i) dis[i] = inf;
que.push(S), dis[S] = 0, fl[S] = inf;
while(!que.empty()){
fro = que.front(), que.pop();
for(int i = head[fro], vv; ~i; i = edge[i].next){
vv = edge[i].v;
if(edge[i].f > 0 && dis[vv] > dis[fro] + edge[i].w)
dis[vv] = dis[fro] + edge[i].w, pre[vv] = i, fl[vv] = min(edge[i].f, fl[fro]), que.push(vv);
}
}
return dis[T] != inf;
}
inline void update(){
int i = T, j;
while(i != S){
j = pre[i], edge[j].f -= fl[T],
edge[j ^ 1].f += fl[T], i = edge[j ^ 1].v;
}
mxf += fl[T], mc += fl[T] * dis[T];
}
void EK(){
while(spfa()) update();
}
int main(){
memset(head, -1, sizeof(head));
scanf("%d%d", &n, &m);
S = n + 2, T = n + 3;//!
for(int i = 1, x; i <= n; ++i)
scanf("%d", &x), addedge(i, i + 1, inf - x, 0);
addedge(S, 1, inf, 0), addedge(n + 1, T, inf, 0);
for(int i = 1, x, y, z; i <= m; ++i)
scanf("%d%d%d", &x, &y, &z), addedge(x, y + 1, inf, z);
EK();
printf("%lld", mc);
return 0;
}