[计算几何][dp] Luogu P1995 智能车比赛
题解
- 题目的给的数据保证矩形是从左往右的(即第i个矩形的右界与第i+1个矩形的左界重合)
- 而且很容易就能够看出,通过两点之间线段最短说明路程一定是折线或线段
- 如果是折线的话拐点一定是位于矩形的顶点,与此同时拐点位于重合的边上,那么每个矩形产生两个点,这一张联通图最多只有(2*N+2)个点
- 然后就可以设f[i]表示起点到i的最短路径,Ffi]=min(f[i],f[j]+len(i,j)
- 我们只要通过斜率去维护这个范围就行了
代码
1 #include <cmath> 2 #include <cstdio> 3 #include <iostream> 4 #include <algorithm> 5 #define N 2010 6 #define sqr(x) (x)*(x) 7 using namespace std; 8 struct node { int x,y; }p[N*3]; 9 int n,px,py,qx,qy,num,a[10],x1[N],y3[N],x2[N],y2[N]; 10 double P,dis[N*2]; 11 void work() 12 { 13 num=1,p[1].x=px,p[1].y=py; 14 for (int i=1;i<n;i++) 15 if (px<=x2[i]) 16 { 17 if (x2[i]>qx) break; 18 a[1]=y3[i],a[2]=y2[i],a[3]=y3[i+1],a[4]=y2[i+1],sort(a+1,a+4+1); 19 p[++num]=(node){x2[i],a[2]},p[++num]=(node){x2[i],a[3]}; 20 } 21 p[++num]=(node){qx,qy}; 22 } 23 int main() 24 { 25 scanf("%d",&n); 26 for (int i=1;i<=n;i++) scanf("%d%d%d%d",&x1[i],&y3[i],&x2[i],&y2[i]); 27 scanf("%d%d%d%d",&px,&py,&qx,&qy); 28 if (px>qx) swap(px,qx),swap(py,qy); 29 scanf("%lf",&P),work(); 30 for (int i=2;i<=num;i++) dis[i]=1e99; 31 for (int i=1;i<=num;i++) 32 { 33 double X=(double)p[i].x*1.0,Y=(double)p[i].y*1.0,mx=1e99,mn=-1e99; 34 for (int j=i+1;j<=num;j++) 35 { 36 double xx=(double)p[j].x*1.0,yy=(double)p[j].y*1.0,len; 37 if (xx==X) { len=abs(Y-yy),dis[j]=min(dis[j],len+dis[i]); continue; } 38 double tmp=(yy-Y)/(xx-X); 39 if (tmp<=mx&&tmp>=mn) 40 { 41 double r=sqr(yy-Y)+sqr(xx-X); 42 len=sqrt(r),dis[j]=min(dis[j],len+dis[i]); 43 } 44 if (j%2==0) mn=max(mn,tmp); else mx=min(mx,tmp); 45 } 46 } 47 printf("%.10lf\n",dis[num]/P); 48 }