## 正解思路

• 因为下表面是可以走的，所以不能直接算s点和t点展开的直线距离。
• 枚举经过下表面的每一条边，再在每条边上三分求出最短距离。注意最短距离的初始值要设为不经过下表面任何一条边的最短距离。

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

## 详细链接

#include<bits/stdc++.h>#define ll long longusing 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;}

#include <bits/stdc++.h>using namespace std;const double eps = 1e-8;const double inf = 1e20;const double pi = acos(-1.0);const int N = 1e5+7;//Compares a double to zeroint sgn(double x){    if(fabs(x) < eps)return 0;    if(x < 0)return-1;    else return 1;}//square of a doubleinline double sqr(double x){return x*x;} struct Point{    double x,y;Point(){}    Point(double _x,double _y){        x = _x;        y = _y;    }    void input(){        scanf("%lf%lf",&x,&y);    }    void output(){        printf("%.2f-%.2f\n",x,y);    }    bool operator == (Point b)const{        return sgn(x-b.x) == 0 && sgn(y-b.y) == 0;    }    bool operator < (Point b)const{        return sgn(x-b.x)== 0-sgn(y-b.y)?0:x<b.x;    }    Point operator-(const Point &b)const{        return Point(x-b.x,y-b.y);    }    //叉积    double operator ^(const Point &b)const{        return x*b.y-y*b.x;    }    //点积    double operator *(const Point &b)const{        return x*b.x + y*b.y;    }    //返回长度    double len(){        return hypot(x,y);//库函数    }    //返回长度的平方    double len2(){        return x*x + y*y;    }    //返回两点的距离    double distance(Point p){        return hypot(x-p.x,y-p.y);    }    Point operator +(const Point &b)const{        return Point(x+b.x,y+b.y);    }    Point operator *(const double &k)const{        return Point(x*k,y*k);    }    Point operator /(const double &k)const{        return Point(x/k,y/k);    }    //计算 pa 和 pb 的夹角    //就是求这个点看 a,b 所成的夹角    //测试 LightOJ1203    double rad(Point a,Point b){        Point p = *this;        return fabs(atan2( fabs((a-p)^(b-p)),(a-p)*(b-p) ));    }    //化为长度为 r 的向量    Point trunc(double r){        double l = len();        if(!sgn(l))return *this;        r /= l;        return Point(x*r,y*r);    }    //逆时针旋转 90 度    Point rotleft(){        return Point(-y,x);    }    //顺时针旋转 90 度    Point rotright(){        return Point(y,-x);    }    //绕着 p 点逆时针旋转 angle    Point rotate(Point p,double angle){        Point v = (*this)-p;        double c = cos(angle), s = sin(angle);        return Point(p.x + v.x*c-v.y*s,p.y + v.x*s + v.y*c);    }}p[N];struct Line{    Point s,e;Line(){}    Line(Point _s,Point _e){        s = _s;        e = _e;    }    bool operator ==(Line v){        return (s == v.s)&&(e == v.e);    }    //根据一个点和倾斜角 angle 确定直线,0<=angle<pi    Line(Point p,double angle){        s = p;        if(sgn(angle-pi/2) == 0){            e = (s + Point(0,1));        }        else{            e = (s + Point(1,tan(angle)));        }    }    //ax+by+c=0    Line(double a,double b,double c){        if(sgn(a) == 0){            s = Point(0,-c/b);            e = Point(1,-c/b);        }        else if(sgn(b) == 0){            s = Point(-c/a,0);            e = Point(-c/a,1);        }        else{            s = Point(0,-c/b);            e = Point(1,(-c-a)/b);        }    }    void input(){        s.input();        e.input();    }    void adjust(){        if(e < s){            swap(s,e);        }    }    //求线段长度    double length(){        return s.distance(e);    }    //返回直线倾斜角 0<=angle<pi    double angle(){        double k = atan2(e.y-s.y,e.x-s.x);        if(sgn(k) < 0)k += pi;        if(sgn(k-pi) == 0)k-= pi;        return k;    }    //点和直线关系    //1 在左侧    //2 在右侧    //3 在直线上    int relation(Point p){        int c = sgn((p-s)^(e-s));        if(c < 0)return 1;        else if(c > 0)return 2;        else return 3;    }    // 点在线段上的判断    bool pointonseg(Point p){        return sgn((p-s)^(e-s)) == 0 && sgn((p-s)*(p-e)) <= 0;    }    //两向量平行 (对应直线平行或重合)    bool parallel(Line v){        return sgn((e-s)^(v.e-v.s)) == 0;    }    //两线段相交判断    //2 规范相交    //1 非规范相交    //0 不相交    int segcrossseg(Line v){        int d1 = sgn((e-s)^(v.s-s));        int d2 = sgn((e-s)^(v.e-s));        int d3 = sgn((v.e-v.s)^(s-v.s));        int d4 = sgn((v.e-v.s)^(e-v.s));        if( (d1^d2)==-2 && (d3^d4)==-2 )return 2;        return (d1==0 && sgn((v.s-s)*(v.s-e))<=0) ||        (d2==0 && sgn((v.e-s)*(v.e-e))<=0) ||        (d3==0 && sgn((s-v.s)*(s-v.e))<=0) ||        (d4==0 && sgn((e-v.s)*(e-v.e))<=0);    }    //直线和线段相交判断    //-*this line -v seg    //2 规范相交    //1 非规范相交    //0 不相交    int linecrossseg(Line v){        int d1 = sgn((e-s)^(v.s-s));        int d2 = sgn((e-s)^(v.e-s));        if((d1^d2)==-2) return 2;        return (d1==0||d2==0);    }    //两直线关系    //0 平行    //1 重合    //2 相交    int linecrossline(Line v){        if((*this).parallel(v))        return v.relation(s)==3;        return 2;    }    //求两直线的交点    //要保证两直线不平行或重合    Point crosspoint(Line v){        double a1 = (v.e-v.s)^(s-v.s);        double a2 = (v.e-v.s)^(e-v.s);        return Point((s.x*a2-e.x*a1)/(a2-a1),(s.y*a2-e.y*a1)/(a2-a1        ));    }    //点到直线的距离    double dispointtoline(Point p){        return fabs((p-s)^(e-s))/length();    }    //点到线段的距离    double dispointtoseg(Point p){        if(sgn((p-s)*(e-s))<0 || sgn((p-e)*(s-e))<0)        return min(p.distance(s),p.distance(e));        return dispointtoline(p);    }    //返回线段到线段的距离    //前提是两线段不相交，相交距离就是 0 了    double dissegtoseg(Line v){        return min(min(dispointtoseg(v.s),dispointtoseg(v.e)),min(v        .dispointtoseg(s),v.dispointtoseg(e)));    }    //返回点 p 在直线上的投影    Point lineprog(Point p){        return s + ( ((e-s)*((e-s)*(p-s)))/((e-s).len2()) );    }    //返回点 p 关于直线的对称点    Point symmetrypoint(Point p){        Point q = lineprog(p);        return Point(2*q.x-p.x,2*q.y-p.y);    }};double sum[N],ans=1e18;int s,t;void work(Point x,Line tmp,int i){    Line res=Line(x,p[t]);    //printf("%lf\n",res.length());    if(res.linecrossseg(tmp)!=0){        ans=min(ans,res.length());        }}int main(){    int n,h;    scanf("%d%d",&n,&h);    for(int i=0;i<n;i++){        p[i].input();    }    scanf("%d%d",&s,&t);    --s; --t;    for(int i=1;i<n;i++){        sum[i]=sum[i-1]+p[i-1].distance(p[i]);    }    double tot=sum[n]=sum[n-1]+p[n-1].distance(p[0]);    for(int i=0;i<n;i++){        Point x=p[i],y=p[(i+1)%n];        Point z=(x-y).rotleft();        z=z*(h*1.0/z.len());                 Point t=y+z;                Line tmp=Line(t,t+z.rotleft());        //printf("%lf\n",tot);        double len;        if(s>=i+1){            len=sum[s]-sum[i+1];        }else{            len=tot-sum[i+1]+sum[s];        }        Point l,r;        l=t+(tmp.e-tmp.s)/tmp.length()*len;        r=t+(tmp.e-tmp.s)/tmp.length()*(len-tot);//        cout<<i<<" "<<r.x<<" "<<r.y<<endl;        work(l,Line(x,y),i);        work(r,Line(x,y),i);        }    printf("%.6lf\n",ans);}