Blog of RuSun

\begin {array}{c} \mathfrak {One Problem Is Difficult} \\\\ \mathfrak {Because You Don't Know} \\\\ \mathfrak {Why It Is Diffucult} \end {array}

P4377 [USACO18OPEN] Talent Show G

P4377 [USACO18OPEN] Talent Show G

比值问题,分数规划,先推式子。
$$
\begin {array}
& \frac {\sum _ {i = 1} ^ n w _ i} {\sum _ {i = 1} ^ n v _ i} \ge mid \\
\sum _ {i = 1} ^ n w _ i \ge mid \sum _ {i = 1} ^ n v _ i \\
\sum _ {i = 1} ^ n w _ i - mid \times v _ i \ge 0
\end {array}
$$

要求 $V$ 满足最小值,大于 $V$ 时就存在 $V$ 即可。

查看代码
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
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 260, M = 1e3 + 10;
const double eps = 1e-5, inf = 1e9;
int n, V, v[N], w[N];
double f[M];
bool check(double mid)
{
for (int i = 0; i <= V; i++)
f[i] = -inf;
f[0] = 0;
for (int i = 1; i <= n; i++)
for (int j = V; j >= 0; j--)
f[min(V, j + v[i])] = max(f[min(V, j + v[i])], f[j] + w[i] - mid * v[i]);
return f[V] > -eps;
}
int main()
{
scanf("%d%d", &n, &V);
for (int i = 1; i <= n; i++)
scanf("%d%d", &v[i], &w[i]);
double l = 0, r = 25e4;
while (r - l > eps)
{
double mid = (l + r) / 2;
if (check(mid))
l = mid;
else
r = mid;
}
printf("%d", (int)(l * 1000));
return 0;
}