对于悬崖上连续的三个点,它们构成的形状可以分为两类:“<”形(高点与低点的连线不穿过悬崖)与 “>”形。
(高点与低点的连线穿过了悬崖)
对于“>”形,从顶端到达底端的最短路径就是顺着形状走,而对于“<”形状,从顶端到达底端的最短路径可以忽
略中间的点,即顶端到底端的连线。
所以最短的路径应当是许多“>”形组成的形状,并且只要构成了这种形状,那么在路径中任取三个点,它们构成
的也都是“>”形。
假设我们已经求出了一条从0到i的最短路径a[0...j],那么从0到i+1的最短路径只需要考虑a[j-1]、a[j]与
i+1三个点所构成的形状。若为“>”形,则为最短路径;若为“<”形,则点a[j]是可以忽略的,此时则要考察点
a[j-2]与a[j-1]和i+1三个点构成的关系,直到满足“>”形。
```#include<iostream>
#include<vector>
#include<algorithm>
#include<cmath>
using namespace std;
int n;
int A[100010][2];
signed main()
{
cin>>n;
for(int i = n ; i >=0 ;i--)
{
cin>>A[i][0];
A[i][1]=n-i;
}
vector<int> B;
B.reserve(n);
for(int i = 0 ; i < n+1 ;i++)
{
if(B.size() < 2)
{
B.push_back(i);
continue;
}
int l2 = B[B.size()-1];
int l1 = B[B.size()-2];
if( (double)(A[l2][1]-A[i][1])*(A[l1][0]-A[i][0]) >= (double)(A[l2][0]-A[i][0])*(A[l1][1]-A[i][1]))
{
B.pop_back();
i--;
}
else
B.push_back(i);
}
long double sum = 0;
for(unsigned int i = 1; i < B.size(); i++)
sum += sqrt(pow((A[ B[i] ][1]-A[ B[i-1] ][1]),2) + pow((A[ B[i] ][0]-A[ B[i-1] ][0]),2));
printf("%.9Lf",sum);
return 0;
}