喷水装置【一】
题目来源于网上,南阳理工大学的acm练习
描述
现有一块草坪,长为20米,宽为2米,要在横中心线上放置半径为Ri的喷水装置,每个喷水装置的效果都会让以它为中心的半径为实数Ri(0
输入
第一行m表示有m组测试数据
每一组测试数据的第一行有一个整数数n,n表示共有n个喷水装置,随后的一行,有n个实数ri,ri表示该喷水装置能覆盖的圆的半径。
输出
输出所用装置的个数
0.0 审题
拿到题目先审题,题目里有两个东西,喷水装置和草坪,每个喷水装置可以浇灌一定圆面积的草坪,草坪是一个20*2的长方形,要求用最少的喷水装置浇灌草坪,输出最小的这个数量。
容易想到如果能写出一个判断二维几何图形是否重合函数的话,就应该能解决这个问题但思考一下就能发现这个函数很难写的,那如果写一维线段是否重合呢?我们发现这个函数就很好写了。所以我们接下来就先把题目抽象化简成一个比较一维区间的问题。
0.1 化简题目
容易发现题目的图像是上下对称的,所以我们只要保证上方被覆盖就可以满足要求,因为要转化为一维区间的比较,我们用一些横线去截图像,横线从中轴线往上扫,可以看出当横线与上方边界重合时边界的区间有最小值,于是我猜测原题等价于在中轴线上的圆与上边界的重合部分可以覆盖整个上边界。那么我们就来试着证明一下。
0.1.1 ## 必要性
如果上边界被全覆盖,那么整个草坪肯定被覆盖,所以得必要性。
0.1.2 ## 充分性
如果整个草坪被覆盖,那么上边界肯定被覆盖,所以得充分性。
0.2 ## 进一步的分析
由上述分析我们已经将题目转化为比较喷水圆与上边界的交线是否覆盖整条上边界。那么这些圆怎么放呢?易得我们安放这些圆于图片中使得其与上边界的左交点为上边界左顶点或已放置圆的右交点,而安放的顺序应该是按照先放大的再放小的,以保证所需的最少。按照这个思路,我们只要算出所有喷水装置与上边界的交线长度(与位置无关)并从大到小排序累加,当和大于20时,已加的喷水装置个数即为最小数量。以上就将原题化简为了一个易与编写的等价命题。
1.0 ## 代码部分
以下为按照上述思路编写的代码,先构造了一个喷水装置的类便于调用其相关数据。
1.1
class watering
{
double ri;
double range;
public:
watering(){ ri = 0; range = 0; }
watering(double r)
{
ri = r;
range = 2 * pow(ri*ri - 1, 0.5);
}
void set_watering(double r)
{
ri = r;
range = 2 * pow(ri*ri - 1, 0.5);
}
double get_range(){ return range; }
double get_ri(){ return ri; }
};
很简单的类,就不多说了