BZOJ 1857: [Scoi2010]传送带(三分套三分)

时间:2019-09-20
本文章向大家介绍BZOJ 1857: [Scoi2010]传送带(三分套三分),主要包括BZOJ 1857: [Scoi2010]传送带(三分套三分)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
Time Limit: 1 Sec Memory Limit: 64 MB
Submit: 2549 Solved: 1370
[Submit][Status][Discuss]

Description

在一个2维平面上有两条传送带,每一条传送带可以看成是一条线段。两条传送带分别为线段AB和线段CD。lxhgww在AB上的移动速度为P,在CD上的移动速度为Q,在平面上的移动速度R。现在lxhgww想从A点走到D点,他想知道最少需要走多长时间

Input

输入数据第一行是4个整数,表示A和B的坐标,分别为Ax,Ay,Bx,By 第二行是4个整数,表示C和D的坐标,分别为Cx,Cy,Dx,Dy 第三行是3个整数,分别是P,Q,R

Output

输出数据为一行,表示lxhgww从A点走到D点的最短时间,保留到小数点后2位

Sample Input

0 0 0 100

100 0 100 100

2 2 1

Sample Output

136.60

HINT

对于100%的数据,1<= Ax,Ay,Bx,By,Cx,Cy,Dx,Dy<=1000
1<=P,Q,R<=10

思路

大概算是三分的模板题

在线段AB和线段CD分别选一个点E,F。假设所需的最短时间的路径为:A->E->F->D

然后单独拿出来E->F->D这条路径,将F->D这条路缩成一个点,再将E->F->D这条路径缩成一个点,计算A点到E点的花费时间,再加上E->F->D路径所花费的最短时间即可

可以知道(并不知道),E点到F->D这个距离花费随着E点坐标的变化,是一个凸函数的函数关系,A点到E->F->D也是一个凸函数(证明看这里:戳我戳我

所以我们可以先假设E点已经找到,然后线段CD上三分寻找F点的位置,使得E->F->D的花费最小

然后在线段AB上三分E点的位置,最后将两段的花费加起来就是最小的花费。

代码

#include <bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define ms(a,b) memset(a,b,sizeof(a))
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int maxn=1e6+10;
const int mod=1e9+7;
const int maxm=1e3+10;
const double eps=1e-8;
using namespace std;
struct point
{
    double x,y;
};
point a,b,c,d;
double P,Q,R;
inline double dis(point a,point b)
{
    double dx=a.x-b.x;
    double dy=a.y-b.y;
    return sqrt(dx*dx+dy*dy);
}
inline double F(point E,point F)
{
    return dis(E,F)/R+dis(F,d)/Q;
}
inline double sanfen(point E,point l,point r)
{
    point mid,midr;
    while(dis(l,r)>eps)
    {
        mid.x=(l.x+r.x)/2;
        mid.y=(l.y+r.y)/2;
        midr.x=(mid.x+r.x)/2;
        midr.y=(mid.y+r.y)/2;
        if(F(E,mid)>F(E,midr))
            l.x=mid.x,l.y=mid.y;
        else
            r.x=midr.x,r.y=midr.y;
    }
    return F(E,l);
}
inline double solve(point l,point r)
{
    point mid,midr;
    while(dis(l,r)>eps)
    {
        mid.x=(l.x+r.x)/2;
        mid.y=(l.y+r.y)/2;
        midr.x=(mid.x+r.x)/2;
        midr.y=(mid.y+r.y)/2;
        double ans1=dis(a,mid)/P+sanfen(mid,c,d);
        double ans2=dis(a,midr)/P+sanfen(midr,c,d);
        if(ans1>ans2)
            l.x=mid.x,l.y=mid.y;
        else
            r.x=midr.x,r.y=midr.y;
    }
    return dis(a,l)/P+sanfen(l,c,d);
}
int main(int argc, char const *argv[])
{
    #ifndef ONLINE_JUDGE
        freopen("/home/wzy/in.txt", "r", stdin);
        freopen("/home/wzy/out.txt", "w", stdout);
        srand((unsigned int)time(NULL));
    #endif
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin>>a.x>>a.y>>b.x>>b.y;
    cin>>c.x>>c.y>>d.x>>d.y;
    cin>>P>>Q>>R;
    cout<<fixed<<setprecision(2)<<solve(a,b)<<endl;
    #ifndef ONLINE_JUDGE
        cerr<<"Time elapsed: "<<1.0*clock()/CLOCKS_PER_SEC<<" s."<<endl;
    #endif
    return 0;
}

原文地址:https://www.cnblogs.com/Friends-A/p/11558478.html