UVa 12407 Speed Zones
問題
n個の層があり、i番目の層は、
y座標y = i * 100からy = (i + 1) * 100の、x軸方向に無限に伸びる帯になっている。
i番目の層を進む速度は、方向にかかわらずs[i]である。
いま、(0, 0)を出発して、(D, n * 100)の地点に到達したい。
最短でどれだけの時間がかかるか、求めよ。
制約条件
n≦100
0≦D≦10000
テストケースは50個以下。
方針
ラグランジュの未定乗数法による。
i番目の層における、x軸方向の移動量をxiと置く。
すると、目的関数fは、移動にかかる時間の合計なので、
f = √(1 + xi^2) / si
ここに、制約条件D = Σxiがかかる。
よってg = Σxi - D
f - λgと置くと、ラグランジュの未定乗数法より、fを最小にするxについて、
∂(f - λg) / ∂xi = 0が成り立つ。
これをλについて解くと、
D = Σλs[i] / √(1 - λ^2s[i]^2)という式が出てくる。
右辺はλについての増加関数であるので、
等号を成り立たせるλは二分探索で見つけられる。
ここから、xiが求まるため、かかる時間が求まる。
ソースコード
int n; double s[100], d, x[100]; int main(){ int CS; cin >> CS; rep(cs, CS){ cin >> n >> d; rep(i, n) cin >> s[i], s[i] /= 100; d /= 100; double lo = 0, hi = INF, mid; rep(i, n) hi = min(hi, 1 / s[i]); lo = -hi; rep(i, 100){ mid = (lo + hi) / 2; double sum = 0; rep(j, n) sum += mid * s[j] / sqrt(1 - mid * mid * s[j] * s[j]); if(sum > d) hi = mid; else lo = mid; } double ans = 0; rep(i, n){ x[i] = mid * s[i] / sqrt(1 - mid * mid * s[i] * s[i]); ans += sqrt(1 + x[i] * x[i]) / s[i]; } printf("Case %d: %.9f\n", cs + 1, ans); } return 0; }