• bzoj1061 志愿者招募


    bzoj1061 志愿者招募

    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。

    解法

    此题真是神坑,根据流量平衡可以得出解法。

    我们设第(i)类志愿者用了(X_i)人,(Y ge 0),可以得出:
    (sum X_i = Y_j + A_j (S_i le j le T_i) ag{1})
    考虑第(i)天与第(i+1)天:
    (sum X_i = Y_{j+1} + A_{j+1} (S_i le j + 1 le T_i) ag{2})
    1,2做差可得:
    (sum_{T_i=j} X_i - sum_{S_i=j+1} X_i = Y_j - Y_{j+1} + A_j - A_{j+1})
    模仿流量平衡方程,我们就可以建立费用流模型,之后用朴素的mcf都可以过。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    #define inf 0x3f3f3f3f
    typedef int edge[50003], vert[1003];
    edge nt, c, w, to;
    vert d, hd, q, from;
    int ce, T;
    bool inq[1003];
    inline void adde(int x, int y, int z, int v) {
    	to[ce] = y, nt[ce] = hd[x];
    	c[ce] = z, w[ce] = v;
    	hd[x] = ce++;
    }
    #define nxt(i) (++(i)>=1003?i=0:i)
    inline bool SPFA() {
    	static int u, v, i, l, r;
    	for (i = 1; i <= T; ++i) d[i] = inf;
    	d[0] = 0; q[0] = 0; from[0] = -1;
    	for (l = 0, r = 1; l ^ r; ) {
    		u = q[l]; nxt(l);
    		for (i = hd[u]; ~i; i = nt[i])
    			if (c[i] && d[v = to[i]] > w[i] + d[u]) {
    				d[v] = w[i] + d[u];
    				from[v] = i;
    				if (!inq[v]) inq[v] = true, q[r] = v, nxt(r);
    			}
    		inq[u] = false;
    	}
    	return d[T] < inf;
    }
    
    inline int mcf() {
    	static int f, e, ret;
    	for (f = inf, e = from[T], ret = 0; ~e; e = from[to[e^1]]) f = min(f, c[e]), ret += w[e];
    	for (e = from[T]; ~e; e = from[to[e^1]]) c[e] -= f, c[e^1] += f;
    	return f * ret;
    }
    
    int main() {
    	int n, m, i, x, y, v;
    	memset(hd, -1, sizeof hd);
    	scanf("%d%d", &n, &m);
    	T = n + 2;
    	for (y = 0, i = 1; i <= n; ++i) {
    		scanf("%d", &x);
    		v = x - y;
    		y = x;
    		if (v > 0) adde(0, i, v, 0), adde(i, 0, 0, 0);
    		else adde(i, T, -v, 0), adde(T, i, 0, 0);
    		adde(i + 1, i, inf, 0), adde(i, i + 1, 0, 0);
    	}
    	adde(n + 1, T, y, 0), adde(T, n + 1, 0, 0);
    	while (m--) {
    		scanf("%d%d%d", &x, &y, &v);
    		++y;
    		adde(x, y, inf, v), adde(y, x, 0, -v);
    	}
    	v = 0;
    	while (SPFA())
    		v += mcf();
    	printf("%d
    ", v);
    	return 0;
    }
    

    其实我们可以发现1,2就是线性规划的标准形式,直接单纯形法。

    #include <cmath>
    #include <cstdio>
    inline int gi() {
    	static int a; static char c;
    	while ((c = getchar()) < '0'); a = c - '0';
    	while ('-' < (c = getchar())) a = (a << 3) + (a << 1) + c - '0';
    	return a;
    }
    const int N = 1003, M = 10003;
    const double inf = 1e9, eps = 1e-9;
    int n, m;
    double a[M][N], b[M], c[N], v;
    void pivot(int l, int e) {
    	static int i, j;
    	b[l] /= a[l][e];
    	for (j = 1; j <= n; ++j) if (j ^ e) a[l][j] /= a[l][e];
    	a[l][e] = 1 / a[l][e];
    	for (i = 1; i <= m; ++i)
    		if ((i ^ l) && fabs(a[i][e]) > 0) {
    			b[i] -= a[i][e] * b[l];
    			for (j = 1; j <= n; ++j) if (j ^ e) a[i][j] -= a[i][e] * a[l][j];
    			a[i][e] = -a[i][e] * a[l][e];
    		}
    	v += c[e] * b[l];
    	for (j = 1; j <= n; ++j) if (j ^ e) c[j] -= c[e] * a[l][j];
    	c[e] = -c[e] * a[l][e];
    }
    double simplex() {
    	int e, l, i;
    	double mn;
    	while (true) {
    		for (e = 1; e <= n; ++e) if(c[e] > eps) break;
    		if (e > n) return v;
    		for (i = 1, mn = inf; i <= m; ++i)
    			if (a[i][e] > eps && mn > b[i] / a[i][e]) mn = b[i] / a[i][e], l = i;
    		if (mn == inf) return inf;
    		pivot(l, e);
    	}
    }
    int main() {
    	int i, j, s, t;
    	n = gi(), m = gi();
    	for (i = 1; i <= n; ++i) c[i] = gi();
    	for (i = 1; i <= m; ++i) {
    		s = gi(), t = gi();
    		for (j = s; j <= t; ++j) a[i][j] = 1;
    		b[i] = gi();
    	}
    	printf("%d", (int)(simplex() + 0.5));
    	return 0;
    }
    
  • 相关阅读:
    JavaScript自动化构建工具grunt、gulp、webpack介绍
    开始使用 Vuejs 2.0 ---简单总结2
    开始使用 Vuejs 2.0 ---简单总结1
    Bootboxjs快速制作Bootstrap的弹出框效果
    FlexSlider是一个非常出色的jQuery滑动切换插件
    CSS实现背景透明,文字不透明(兼容各浏览器)
    jquery中attr和prop的区别
    GitHub 的分支创建与合并
    [译]使用NuGet管理共享代码
    [译]Nuget.Server
  • 原文地址:https://www.cnblogs.com/cycleke/p/6286833.html
Copyright © 2020-2023  润新知