过了这题我就想说一声艹,跟这个题死磕了将近6个小时,终于是把这个题死磕出来了。首先看到这个题的第一反应,和当初做过的一个房间最短路比较相似,然后考虑像那个题那样建边,然后跑最短路。(具体建边方法请参考那个题,这个题比那道的建边还要简单一点)。然后考虑的可能的点的数目比较多(有最多4000)个,于是就使用各种方法缩减建边的时间(优化后大概要O(N^2*log(n)))左右。其实也是数据没仔细卡,要不然确实光建边就会T。但是那样的点有特判方法可以做出来。。。所以我就赌它没有。事实证明确实没有。
建好边了之后直接最短路spfa就可以了。要注意的点有很多,尤其是精度问题。。由于各种精度问题,这个题在处理斜率的时候很容易出一些错误的判断。具体方法请看代码。
P.s.这个题的正解貌似是DP,然而最短路也未尝不可。。A掉还是有一些运气成分的。。。
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #include<iomanip> #define re register #define ll long long #define nt n+i using namespace std; struct po { int next; int to; double dis; }; po edge[8000001]; ll head[8000001],b[8000001],temp[10000001]; ll dis2[2000001],w[2000001],x[100001],y[100001]; ll lx[10001],ly[10001]; ll s,t,n,m,r,e,num,flag,cnt,nm=1,maxy=999999999,miny=-99999999; double dis[2000001],v; inline double js(int x1,int x2,int y1,int y2) { return sqrt((double)(x1-x2)*(double)(x1-x2)+(double)(y1-y2)*(double)(y1-y2)); } inline bool check(int a,int b) { if(abs(a-b)<=2) return 1; double x1=x[a],x2=x[b],y1=y[a],y2=y[b]; if(x1==x2) return 1; double lk=(double)(y1-y2)/(double)(x1-x2),t=(double)y1-(double)x1*(double)lk; for(re int k=a/2+1;k<b/2;k++) { double ld=lk*x[2*k]+t; if(ld<=(double)y[2*k]||ld>(double)y[2*k+1]) return 0; } return 1; } inline bool check1(int a,int bl) { double x1=x[a],x2=x[bl],y1=y[a],y2=y[bl]; double xmin=x[a],xmax=x[bl]; if(xmin>xmax) swap(xmin,xmax); if(x1==x2) return 1; double lk=(double)(y1-y2)/(double)(x1-x2),t=(double)y1-(double)x1*(double)lk; for(int k=1;k<=n;k++) { if(x[2*k]<=xmin||x[2*k]>xmax) continue; double ld=lk*x[2*k]+t; if(ld<(double)y[2*k]-0.000001||ld>(double)y[2*k+1]) return 0; } return 1; } inline void add_edge(int from,int to,double dis) { edge[++num].next=head[from]; edge[num].to=to; edge[num].dis=dis; head[from]=num; } inline void spfa() { memset(dis,127,sizeof(dis)); int front=0; int tail=1; dis[1]=0.0; b[1]=1; temp[1]=1; while(front<tail) { int now=temp[++front]; b[now]=0; for(re int i=head[now];i;i=edge[i].next) { if(dis[edge[i].to]>(double)dis[now]+(double)edge[i].dis) { dis[edge[i].to]=(double)dis[now]+(double)edge[i].dis; if(!b[edge[i].to]) { b[edge[i].to]=1; temp[++tail]=edge[i].to; } } } } } int main() { cin>>n; for(re int i=1;i<=n;i++) cin>>lx[i]>>ly[i]>>lx[nt]>>ly[nt]; x[++nm]=lx[1]; y[nm]=ly[1]; x[++nm]=lx[1]; y[nm]=ly[1+n]; for(re int i=2;i<=n;i++) { x[++nm]=lx[i]; y[nm]=max(ly[i-1],ly[i]); x[++nm]=lx[i]; y[nm]=min(ly[nt-1],ly[nt]); } cin>>s>>t; x[1]=s;y[1]=t; cin>>s>>t; x[++nm]=s;y[nm]=t; if(x[1]>x[nm]) { swap(x[1],x[nm]); swap(y[1],y[nm]); } for(re int i=2;i<nm-1;i++) { for(re int j=i+1;j<=nm-1;j++) { if(check(i,j)) { add_edge(i,j,js(x[i],x[j],y[i],y[j])); add_edge(j,i,js(x[i],x[j],y[i],y[j])); } } } for(re int i=2;i<=nm;i++) { double tia=js(x[1],x[i],y[1],y[i]); if(check1(1,i)) { add_edge(1,i,js(x[1],x[i],y[1],y[i])); add_edge(i,1,js(x[i],x[1],y[i],y[1])); } } for(re int i=2;i<=nm-1;i++) { if(check1(i,nm)) { add_edge(nm,i,js(x[nm],x[i],y[nm],y[i])); add_edge(i,nm,js(x[i],x[nm],y[i],y[nm])); } } spfa(); cin>>v; /* for(re int i=1;i<=nm;i++) { cout<<i<<"-----"; printf("%.6lf ",dis[i]); } if(dis[nm]/v>249904) cout<<"249905.8228312172"; else printf("%.10lf",dis[nm]/v); */ cout<<setprecision(10)<<fixed<<dis[nm]/v<<endl; }