洛谷P3980 [NOI2008]志愿者招募

题解

最小费用最大流

每一天是一条边\((inf-a[i], 0)\)

然后对于一类志愿者,

区间两端连一条\((inf, c[i])\)

\(S\)向第一个点连\((inf, 0)\)

最后一个点向\(T\)\((inf, 0)\)

然后跑最小费用最大流

这为什么是对的?

我们的目的变成用加的那些边,把最大流量填成\(inf\)

求最小费用

Code

#include<bits/stdc++.h>

#define LL long long
#define RG register

using namespace std;
template<class T> inline void read(T &x) {
	x = 0; RG char c = getchar(); bool f = 0;
	while (c != '-' && (c < '0' || c > '9')) c = getchar(); if (c == '-') c = getchar(), f = 1;
	while (c >= '0' && c <= '9') x = x*10+c-48, c = getchar();
	x = f ? -x : x;
	return ;
}
template<class T> inline void write(T x) {
	if (!x) {putchar(48);return ;}
	if (x < 0) x = -x, putchar('-');
	int len = -1, z[20]; while (x > 0) z[++len] = x%10, x /= 10;
	for (RG int i = len; i >= 0; i--) putchar(z[i]+48);return ;
}
const int N = 2010, inf = 2147483647;
int a[N];

struct node {
	int to, nxt, w, v;
}g[2000000];
int last[N], gl = 1;
void add(int x, int y, int w, int v) {
	g[++gl] = (node) {y, last[x], w, v};
	last[x] = gl;
	g[++gl] = (node) {x, last[y], 0, -v};
	last[y] = gl;
}

int s, t;

int dis[N], from[N], pre[N];
bool vis[N];
queue<int> q;

bool spfa() {
	q.push(s);
	memset(dis, 127, sizeof(dis));
	dis[s] = 0;
	while (!q.empty()) {
		int u = q.front(); q.pop();
		for (int i = last[u]; i; i = g[i].nxt) {
			int v = g[i].to;
			if (dis[v] > dis[u] + g[i].v && g[i].w) {
				dis[v] = dis[u] + g[i].v;
				from[v] = i; pre[v] = u;
				if (!vis[v]) {
					vis[v] = 1;
					q.push(v);
				}
			}
		}
		vis[u] = 0;
	}
	return dis[0] != dis[t];
}


int McMf() {
	int ans = 0;
	while (spfa()) {
		int di = inf;
		for (int i = t; i != s; i = pre[i]) di = min(di, g[from[i]].w);
		ans  += di * dis[t];
		for (int i = t; i != s; i = pre[i])
			g[from[i]].w -= di, g[from[i]^1].w += di;
	}	
	return ans;
}

int main() {
	int n, m;
	read(n), read(m);
	for (int i = 1; i <= n; i++) read(a[i]);
	s = n + 2, t = s + 1;
	for (int i = 1; i <= n; i++)
		add(i, i+1, inf - a[i], 0);
	add(s, 1, inf, 0), add(n + 1, t, inf, 0);
	for (int i = 1; i <= m; i++) {
		int S, T, C;
		read(S), read(T), read(C);
		add(S, T+1, inf, C);
	}
	printf("%d\n", McMf());
	return 0;
}

posted @ 2019-03-05 17:26  zzy2005  阅读(118)  评论(0编辑  收藏  举报