题目链接:传送门

Description

一个项目需要NN天完成,第ii天至少需要AiA_i 个人。一共有MM类志愿者可以招募,第ii类可以从第SiS_i 天工作到第TiT_i天,招募费用是每人CiC_i 元。求满足条件的最小费用

Constraints

n1000,m10000n\leq 1000, m \leq 10000,题目中其他所涉及的数据均不超过23112^{31}-1

Solution

这道题原本是一道网络流建模神题,然而确是单纯形裸题

设第 类志愿者招募了 人, 表示第 天第 类志愿者能否工作,把 看做 看做 ,那么就是线性规划比较一般的形式了:

最小化                             j=1ncjxj\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \sum_{j=1}^{n} c_jx_j

满足约束                         j=1nai,jxjbi               i=1,2,...m\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \sum_{j=1}^{n}a_{i,j}x_j \leq b_i\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ i=1,2,...m

                                                        xj0                j=1,2,...n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ x_j \ge 0\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ j=1,2,...n

再对偶一下就变成了

最大化                             i=1mbiyi\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \sum_{i=1}^{m} b_iy_i

满足约束                         i=1mai,jyicj               j=1,2,...n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \sum_{i=1}^{m}a_{i,j}y_i \leq c_j\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ j=1,2,...n

                                                        yi0                i=1,2,...m\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ y_i \ge 0\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ i=1,2,...m

然后直接上单纯形就可以了

单纯形通俗来讲就是通过不断地换元,代入消元来把目标函数cixi\sum{c_ix_i}的系数都变成负数,然后又因为xix_i非负,就能在xix_i都取00的时候求出最大值了

要注意实际存系数的时候没有把它移项,一些正负号的问题要考虑清楚

2016论文集[浅谈线性规划与对偶问题]上对单纯形的讲解比较细致,这两个也讲的比较好:线性规划的单纯形法 - CSDN博客线性规划与单纯形算法

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include <bits/stdc++.h>

#define x first
#define y second
#define x1 X1
#define x2 X2
#define y1 Y1
#define y2 Y2
#define mp make_pair
#define pb push_back

using namespace std;

typedef long long LL;
typedef pair<int, int> pii;

template <typename T> inline int Chkmax (T &a, T b) {return a < b ? a = b, 1 : 0;}
template <typename T> inline int Chkmin (T &a, T b) {return a > b ? a = b, 1 : 0;}
inline int read ()
{
int sum = 0, fl = 1; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') fl = -1;
for (; isdigit(ch); ch = getchar()) sum = (sum << 3) + (sum << 1) + ch - '0';
return sum * fl;
}

const int Maxn = 1000 + 10, Maxm = 10000 + 10;

int N, M;
double A[Maxm][Maxn];

namespace Simplex
{
const double eps = 1e-8;
inline void pivot (int x, int y)
{
double tmp = A[x][y];
for (int j = 0; j <= N; ++j) A[x][j] /= tmp;
for (int i = 0; i <= M; ++i)
if (i != x && abs(A[i][y]) > eps)
{
tmp = A[i][y]; A[i][y] = 0;
for (int j = 0; j <= N; ++j) A[i][j] -= tmp * A[x][j];
}
}

inline void work ()
{
while (1)
{
int x = 0, y = 0;
for (int j = 1; j <= N; ++j) if (A[0][j] > eps) { y = j; break; }
if (!y) return ;
double Min = 1.0 * 0x3f3f3f3f;
for (int i = 1; i <= M; ++i)
if (A[i][y] > eps && A[i][0] / A[i][y] < Min)
Min = A[i][0] / A[i][y], x = i;
if (!x) return ;
pivot(x, y);
}
}
}

int main()
{
#ifdef hk_cnyali
freopen("A.in", "r", stdin);
freopen("A.out", "w", stdout);
#endif
N = read(), M = read();
for (int j = 1; j <= N; ++j) scanf("%lf", &A[0][j]);
for (int i = 1; i <= M; ++i)
{
int x = read(), y = read(); A[i][0] = 1.0 * read();
for (int j = x; j <= y; ++j)
A[i][j] = 1.0;
}
Simplex :: work();
printf("%d\n",(int)(-A[0][0]));
return 0;
}