【[NOI2011]智能车比赛】(建图+spfa+坑爹精度)

过了这题我就想说一声艹,跟这个题死磕了将近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\n",dis[i]);
    }
    if(dis[nm]/v>249904)
    cout<<"249905.8228312172";
    else
    printf("%.10lf",dis[nm]/v);
    */
    cout<<setprecision(10)<<fixed<<dis[nm]/v<<endl;
}

 

posted @ 2018-02-07 15:22  ~victorique~  阅读(302)  评论(0编辑  收藏  举报
Live2D