Official
F - Shortcuts Editorial
by
F - Shortcuts Editorial
by
physics0523
例えば、 個のチェックポイントを無視したとしましょう。
この時 のペナルティが発生しますが、愚直に全てのチェックポイントを回ったとしても距離の総和は 以内で収まるので、この数の無視をするのは明らかに無駄であることが分かります。
この時、以下の DP が成立します:
dp[最後に通ったチェックポイント][無視したチェックポイントの数] = {距離の総和の最小値}
二つ目の添字 は 未満しか考慮しなくて良いことに注意してください。
、その他のテーブルの値は に初期化され、答えは 「 に 個のチェックポイントを無視した際のペナルティを足したもの」の最小値となります。
このことから、考慮する無視の回数の上限を としたとき、時間計算量 でこの問題に正解できます。 ( とするとギリギリになる可能性がありますが、もう少しよい見積をすると実行時間に余裕を持って AC できます。 )
実装例 (C++):
Copy
#include<bits/stdc++.h>
using namespace std;
using pi=pair<int,int>;
long double dist(pi a,pi b){
int dx=a.first-b.first;
int dy=a.second-b.second;
int ss=dx*dx+dy*dy;
return sqrt((long double)ss);
}
long double lg=8.0e18;
int main(){
int n;
cin >> n;
vector<pi> vp(n);
for(int i=0;i<n;i++){
cin >> vp[i].first >> vp[i].second;
}
vector<vector<long double>> dp(n,vector<long double>(60,lg));
dp[0][0]=0.0;
for(int i=1;i<n;i++){
for(int j=i-1;j>=0;j--){
int skip=i-j-1;
for(int k=0;(k+skip)<60;k++){
dp[i][k+skip]=min(dp[i][k+skip],dp[j][k]+dist(vp[j],vp[i]));
}
}
}
long double res=lg;
for(int i=0;i<60;i++){
long double pen=0.0;
if(i>0){
pen=pow(2.0,(long double)(i-1));
}
res=min(res,dp[n-1][i]+pen);
}
printf("%.6Lf\n",res);
return 0;
}
#include<bits/stdc++.h> using namespace std; using pi=pair<int,int>; long double dist(pi a,pi b){ int dx=a.first-b.first; int dy=a.second-b.second; int ss=dx*dx+dy*dy; return sqrt((long double)ss); } long double lg=8.0e18; int main(){ int n; cin >> n; vector<pi> vp(n); for(int i=0;i<n;i++){ cin >> vp[i].first >> vp[i].second; } vector<vector<long double>> dp(n,vector<long double>(60,lg)); dp[0][0]=0.0; for(int i=1;i<n;i++){ for(int j=i-1;j>=0;j--){ int skip=i-j-1; for(int k=0;(k+skip)<60;k++){ dp[i][k+skip]=min(dp[i][k+skip],dp[j][k]+dist(vp[j],vp[i])); } } } long double res=lg; for(int i=0;i<60;i++){ long double pen=0.0; if(i>0){ pen=pow(2.0,(long double)(i-1)); } res=min(res,dp[n-1][i]+pen); } printf("%.6Lf\n",res); return 0; }
posted:
last update: