SRM543 Div1 Medium(500) EllysRivers
普通に動的計画法をするとO(N2length)で間に合わない。終了間際になっても解けなかったので、自信は無かったけど、島iのj番目の港に最短時間で行くときに通る島i-1の港は、島iのj-1番目の港に最短時間で行くときに通る島i-1の港かその両隣、と仮定して書いたら通った。
歩きの移動はどこの島でも同じ速度なので、歩くのは最初の島のみとして良い。
#include <string> #include <vector> #include <cmath> using namespace std; class EllysRivers{public: double getMin( int length, int walk, vector <int> width, vector <int> speed ) { int N = (int)width.size(); vector<double> T(length+1); for ( int i=0; i<=length; i++ ) T[i] = (double)i/walk; for ( int i=0; i<N; i++ ) { vector<double> P = T; T = vector<double>(length+1,1e100); T[0] = P[0]+(double)width[i]/speed[i]; int p = 0; for ( int j=0; j<=length; j++ ) { int s = max(p-1,0); int e = min(p+1,j); for ( int k=s; k<=e; k++ ) { double t = P[k]+hypot(width[i],j-k)/speed[i]; if ( t < T[j] ) { T[j] = t; p = k; } } } } return T[length]; }};
GeRichさんの解答が凄い。歩きでの移動を幅0の海と考える。それぞれの海で、width[i]の移動は常に必要。南北方向に1km移動距離が増えたときの時間の増加を、南北方向の距離ごとに計算して、その中から短い順にlength個の和を取る。例えば、3km→4kmを選ばずに4km→5kmを選んでしまったらマズいけど、距離が長いほど移動時間の増加は少ないので、そんなことはおこらない。
#include <string> #include <vector> #include <cmath> #include <algorithm> #include <numeric> using namespace std; class EllysRivers{public: double getMin( int length, int walk, vector <int> width, vector <int> speed ) { width.push_back(0); speed.push_back(walk); int N = (int)width.size(); double ans = 0; for ( int i=0; i<N; i++ ) ans += (double)width[i]/speed[i]; static double Q[51*100000]; int q = 0; for ( int i=0; i<N; i++ ) for ( int j=1; j<=length; j++ ) Q[q++] = (hypot(width[i],j)-hypot(width[i],j-1))/speed[i]; sort(Q,Q+q); ans += accumulate(Q,Q+length,0.0); return ans; }};