n 段路,第 i 段長 si,以速度 vi 行駛消耗體力 ki(v-v'i)2si。給定體力上限 E,求最大平均速度(即最小總時間)。
目標:最小化 Σ s_i / x_i,約束 Σ k_i (x_i - v_i)^2 s_i ≤ E,x_i ≥ v_i。
拉格朗日函數:L = Σ s_i/x_i + λ(Σ k_i (x_i - v_i)^2 s_i - E)。
對 xi 求導為 0 得:2λ k_i x_i^2 (x_i - v_i) = 1。
對固定 λ,每段最優速度 xi 由上式唯一決定(函數單調遞增)。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 10100;
const double INF = 1e9, EPS = 1e-12;
int n; double E, s[MAXN], k[MAXN], v[MAXN], x[MAXN];
double calc(double lambda) {
double tot = 0;
for (int i = 1; i <= n; ++i) {
double l = max(0.0, v[i]), r = INF;
while (r - l > EPS) {
double mid = (l + r) / 2;
if (2 * lambda * k[i] * mid * mid * (mid - v[i]) > 1) r = mid;
else l = mid;
}
x[i] = (l + r) / 2;
tot += k[i] * (x[i] - v[i]) * (x[i] - v[i]) * s[i];
}
return tot;
}
int main() {
cin >> n >> E;
for (int i = 1; i <= n; ++i) scanf("%lf%lf%lf", &s[i], &k[i], &v[i]);
double l = 0, r = INF;
while (r - l > EPS) {
double mid = (l + r) / 2;
if (calc(mid) >= E) l = mid; else r = mid;
}
double ans = 0;
for (int i = 1; i <= n; ++i) ans += s[i] / x[i];
printf("%.10lf\n", ans);
return 0;
}
這道題展示了數學建模在算法競賽中的威力:將複雜約束優化轉化為可計算的單調方程組。