三分法专练 hdu - Error Curves-3714 & hdu - The Moving Points-4717

3 篇文章 0 订阅

Error Curves

题意

  • 给你n个两次函数 y = ax^2 + bx + c,其中0 ≤ a ≤ 100 ,|b| ≤ 5000), c (|c| ≤ 5000),0≤x≤1000。
  • 定义F(x)为x在[0,1000]这个范围内的所有函数的最大值,求F(x)的最小值。最大指的是对于某一个x最大的那个y,最小指的是全体的x范围中最大的那个最小。

思路

  • 因为a>=0 所以都是开口向上的,如果F(n) 的 x/y( x<= 0 && x <= 1000),图像肯定是单调或者凸性的,所以直接三分就行了。

代码

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;

const double eps=1e-9;
const int maxn=1e5+5;

double a[maxn],b[maxn],c[maxn];
int n;
double cal(double x)
{
    double ans=a[1]*x*x+b[1]*x+c[1];
    for(int i=2;i<=n;i++)
        ans=max(ans,a[i]*x*x+b[i]*x+c[i]);
    return ans;
}
double solve(double l,double r)
{
    double mid,mid2;
    while(r-l>eps){
        mid=(l+r)/2;
        mid2=(mid+r)/2;
        if(cal(mid)>=cal(mid2)){
            l=mid;
        }else r=mid2;
    }
    return cal(l);
}
int main()
{
    int T;
    scanf("%d",&T);
    for(int cas=1;cas<=T;cas++){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%lf%lf%lf",&a[i],&b[i],&c[i]);
        }
        printf("%.4f\n",solve(0,1000));
    }
    return 0;
}

The Moving Points

题意

  • 给定n个点的坐标和它x和y方向的分速度,要求在任意时刻两两点之间距离最大值中的最小值。
  • 根据距离公式可以推断出对于某两个点在t逐渐增大的过程中距离服从二次函数。

思路

  • 易知是凸函数,对于时间t三分求最大距离。枚举范围0~1e10。

代码

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;

const double eps=1e-9;
const int maxn=305;

double x[maxn],y[maxn],vx[maxn],vy[maxn];
int n;
double cal(double t)
{
    double ans=0;
    for(int i=1;i<=n;i++){
        for(int j=i+1;j<=n;j++){
            double x1=x[i]+vx[i]*t;
            double y1=y[i]+vy[i]*t;
            double x2=x[j]+vx[j]*t;
            double y2=y[j]+vy[j]*t;
            ans=max(ans,sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)));
        }
    }
    return ans;
}
double solve(double l,double r)
{
    double mid,mid2;
    while(r-l>eps){
        mid=(l+r)/2;
        mid2=(mid+r)/2;
        if(cal(mid)>=cal(mid2)){
            l=mid;
        }else r=mid2;
    }
    return l;
}
int main()
{
    int T;
    scanf("%d",&T);
    for(int cas=1;cas<=T;cas++){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%lf%lf%lf%lf",&x[i],&y[i],&vx[i],&vy[i]);
        }
        double t=solve(0,1e10);
        printf("Case #%d: %.2lf %.2lf\n",cas,t,cal(t));
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值