题目思路

因为下表面是可以走的,所以不能直接算s点和t点的直线距离。这个时候就要考虑枚举经过下表面的每一条边,再在每条边上三分求出最短距离。注意最短距离的初始值要设为不经过下表面任何一条边的最短距离。复杂度O(nlogn)

slen记录每个顶点到s点的距离,getdis是获得上表面或下表面的两点距离,finddis是获得如果经过下表面某个点的路程距离,tridiv三分。因为我的下标是从0开始的,所以s点是p[s-1]。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int s,t,n;
double ans,slen[100001],h;
pair<double,double>p[100001];
inline double getdis(pair<double,double>p1,pair<double,double>p2)
{
    return sqrt((p1.first-p2.first)*(p1.first-p2.first)+(p1.second-p2.second)*(p1.second-p2.second));
}
inline double finddis(pair<double,double>now,int l,int r)
{
    double len = min(slen[l]+getdis(p[l],now),slen[r]+getdis(p[r],now));
    return sqrt(h*h+len*len)+getdis(now,p[t-1]);
}
inline double tridiv(int l,int r)
{
    double minn = 0x3f3f3f3f;
    pair<double,double> left = p[l];
    pair<double,double> right = p[r];
    while(getdis(left,right)>1e-3)
    {
        pair<double,double> first = make_pair((2*left.first+right.first)/3,(2*left.second+right.second)/3);
        pair<double,double> second = make_pair((left.first+2*right.first)/3,(left.second+2*right.second)/3);
        double firdis = finddis(first,l,r);
        double secdis = finddis(second,l,r);
        if(firdis>secdis)
        {
            left = first;
            minn = min(minn,secdis);
        }
        else
        {
            right = second;
            minn = min(minn,firdis);
        }
    }
    return minn;
}
int main()
{
    scanf("%d%lf",&n,&h);
    for(int i = 0;i<n;i++)
        scanf("%lf%lf",&p[i].first,&p[i].second);
    scanf("%d%d",&s,&t);
    double s1 = 0,s2 = 0,sum = 0;
    int last = s-1;
    slen[last] = 0;
    for(int i = s%n;i!=s-1;i++,i%=n)
    {
        double len = getdis(p[last],p[i]);
        sum+=len;
        slen[i] = slen[last]+len;
        last = i;
    }
    sum+=getdis(p[last],p[s-1]);
    for(int i = 0;i<n;i++)
        slen[i] = min(slen[i],sum-slen[i]);
    ans = sqrt(slen[t-1]*slen[t-1]+h*h);
    last = n-1;
    for(int i = 0;i<n;i++,last++,last%=n)
        ans = min(ans,tridiv(last,i));
    printf("%.6lf",ans);
    return 0;
}
02-11 19:17