[计算几何][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 }

 

posted @ 2019-08-08 19:21  BEYang_Z  阅读(249)  评论(0编辑  收藏  举报