洛谷 P2600 [ZJOI2008]瞭望塔

洛谷 P2600 [ZJOI2008]瞭望塔

洛谷传送门

题目描述

致力于建设全国示范和谐小村庄的H村村长dadzhi,决定在村中建立一个瞭望塔,以此加强村中的治安。

我们将H村抽象为一维的轮廓。如下图所示

img

我们可以用一条山的上方轮廓折线(x1, y1), (x2, y2), …. (xn, yn)来描述H村的形状,这里x1 < x2 < …< xn。瞭望塔可以建造在[x1, xn]间的任意位置, 但必须满足从瞭望塔的顶端可以看到H村的任意位置。可见在不同的位置建造瞭望塔,所需要建造的高度是不同的。为了节省开支,dadzhi村长希望建造的塔高度尽可能小。

请你写一个程序,帮助dadzhi村长计算塔的最小高度。

输入格式

输入文件tower.in第一行包含一个整数n,表示轮廓折线的节点数目。接下来第一行n个整数, 为x1 ~ xn. 第三行n个整数,为y1 ~ yn。

输出格式

输出文件tower.out仅包含一个实数,为塔的最小高度,精确到小数点后三位。


题解:

首先明确,它不一定是在最高的点修塔。很容易就能构造出一种反例来hack掉这种想法。

所以直接选出建塔点之后枚举或二分长度这种想法破灭了。

所以开始考虑选点的问题。

咋选点呢?首先想到二分选点,但是这玩意并不是一个单调函数,理想破灭。

?等等,不单调,可不可以三分。

可以!!

欣喜若狂:发现如果往左建,就要花力气看看右侧的点,如果往右建,就要花力气看看左侧的点。这样的话就可以确定建塔处,至于塔高直接取所有线段反向延长后到此的最大值即可。

应该还是很容易的,对三分不太熟悉的小伙伴可以参照这里:浅谈三分法

代码:

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=310;
const double eps=1e-7;
const double INF=1e20;
int n;
double ans=INF;
struct node
{
    double x,y;
}p[maxn];
struct edge
{
    double k,b;
    bool f;//是否平
}e[maxn];
double calc(double x,double y)
{
    double tmp=0;
    for(int i=1;i<n;i++)
    {
        if(!e[i].f) 
			continue;
        tmp=fmax(tmp,e[i].k*x+e[i].b-y);
    }
    return tmp;
}
bool check(double x1,double x2,int i)
{
	return calc(x1,e[i].k*x1+e[i].b)<calc(x2,e[i].k*x2+e[i].b);
}
int main()
{
	// freopen("cold.in","r",stdin);
	// freopen("cold.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++) 
		scanf("%lf",&p[i].x);
    for(int i=1;i<=n;i++) 
		scanf("%lf",&p[i].y);
    for(int i=1;i<n;i++)
    {
        if(fabs(p[i].x-p[i+1].x)<eps) 
			continue;//平
        e[i].k=(p[i].y-p[i+1].y)/(p[i].x-p[i+1].x);
        e[i].b=p[i].y-p[i].x*e[i].k;
        e[i].f=1;
    }
    for(int i=1;i<n;i++)
    {
        if(!e[i].f) 
			continue;
        int t=612; 
		double l=p[i].x; 
		double r=p[i+1].x;
		double mid1,mid2;
        while(t--)
        {
            mid1=l+(r-l)/3; 
			mid2=r-(r-l)/3;
            if(check(mid1,mid2,i)) 
				r=mid2;
            else 
				l=mid1;
        }
        ans=fmin(ans,calc(mid1,e[i].k*mid1+e[i].b));
    }
    printf("%.3lf",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/fusiwei/p/14019973.html