*zoj - Light-3203 - Bulb - 三分法模板

本文通过一个关于求解豹子影子最大长度的问题引入了三分法的概念,并详细阐述了如何利用三分法来解决此类问题。包括三分法的基本原理、应用步骤及具体的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

Compared to wildleopard’s wealthiness, his brother mildleopard is rather poor. His house is narrow and he has only one light bulb in his house. Every night, he is wandering in his incommodious house, thinking of how to earn more money. One day, he found that the length of his shadow was changing from time to time while walking between the light bulb and the wall of his house. A sudden thought ran through his mind and he wanted to know the maximum length of his shadow.
这里写图片描述

Input

The first line of the input contains an integer T (T <= 100), indicating the number of cases.
Each test case contains three real numbers H, h and D in one line. H is the height of the light bulb while h is the height of mildleopard. D is distance between the light bulb and the wall. All numbers are in range from 10-2 to 103, both inclusive, and H - h >= 10-2.

Output

For each test case, output the maximum length of mildleopard’s shadow in one line, accurate up to three decimal places..

Sample Input

3
2 1 0.5
2 0.5 3
4 3 4

Sample Output

1.000
0.750
4.000

三分法介绍

这里写图片描述
注意

  • 三分法多用在求凹凸函数,求最值。
  • 二分法多用在单调函数求值。
  • 凹凸判断
    • 在图像上任取两点A,B连接,若函数图像在两点间的部分均在直线下方,则把该函数在[A,B]之间的部分定义为凹函数.反之为凸函数。
    • 凹函数:f”(x)>=0原函数为凹函数
      凸函数:f”(x)<=0原函数为凸函数

在 Left 和 Right 取两个点 mid1 和 mid2,把该区间分成三个部分

  • 如果f(mid1)≥f(mid2),则峰值在区间 [Left, mid2] 之间
  • 如果f(mid1)< f(mid2),则峰值在区间 [mid1,Right] 之间

注意:如果是凸函数,上面两个条件恰好相反。 可以看到,每次处理后区间少了一个部分,反复下去,直至区间缩小到满足 精度要求。
mid1 和 mid2 常见有两种取法:

  • mid1=(Left+Right)/2 ,mid2=(mid1+Right)/2,最坏的情况下总是剩下 原区间的 3 4,时间复杂度为O(log4 3n)
  • mid1=Left + (Right - Left)/3 mid2=Right - (Right - Left)/3, 这样总是 剩下原来区间的 2 3,时间复杂度为O(log3 2n)

题解

这里写图片描述

三分法

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

double H,h,D;
const double eps=1e-8;
double f(double x)
{
    return D-x+H-(H-h)*D/x;
}
double ternary_search(double L,double R)
{
    if(L>R) swap(L,R);
    double mid1,mid2;
    while(R-L>eps){
        mid1=(L+R)/2.0;
        mid2=(mid1+R)/2.0;
        if(f(mid1)>=f(mid2))
            R=mid2;
        else
            L=mid1;
    }
    return f(R);
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%lf%lf%lf",&H,&h,&D);
        double l=D-h*D/H,r=D;
        double ans=ternary_search(l,r);
        printf("%.3lf\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值