UVA 10382
UVA 10382 Watering Grass
传送门:洛谷 UVA10382 | UVA 10382 | LibreOJ #10002
题目大意
在一块长 \(L\) 米,宽 \(W\) 米的矩形草坪中共有 \(n\) 个喷水装置,每个喷水装置都在草坪的中心线上(即离两边各 \(\frac{W}{2}\) 米)。
已知:每个喷水装置的位置(即离草坪最左端的距离),以及它能灌溉到的圆形范围的半径。
求问:要确保整块草坪都被灌溉到,则最少需要打开多少个喷水装置?
问题分析
此题为贪心算法中区间覆盖问题的典型例题。
此问题可以转化为:给定多个区间 \([a_i, b_i]\),选择最少的区间,使它们可以覆盖整个区间 \([1, l]\)。
对于上述问题,可以考虑贪心。将所有区间按照左端点从小到大进行排序。假设 \([0, p)\) 已经被覆盖,对于未被覆盖到的点 \(p(0\le p < l)\),枚举所有能覆盖到点 \(p\) 的区间,选择其中右端点最大的区间 \([a, b]\),其中 \(a \le p\)。则覆盖的范围变为了 \([0, b]\)。将 \(p\) 设为 \(b\) 之后的未被覆盖的点(可认为是 \(b\) 本身),继续下次循环。
正确性证明
使用反证法可以证明此贪心解法是最优解。
简单来说,现在区间 \([0, p)\) 均被覆盖,那么对于未被覆盖的点 \(p\),贪心解法是选择能覆盖点 \(p\) 的所有区间中,右端点最大的区间 \([a_x, b_x]\)。如果选择的区间 \([a_y, b_y]\) 右端点不是最大的,即 \(b_y < b_x\),那么选择区间 \([a_x, b_x]\) 能够多选择到区间 \((b_y, b_x]\) ,比该方案更优;如果选择不能覆盖点 \(p\) 的区间,那么还需要再增加一个区间来覆盖点 \(p\)。
本题具体解法
计算每个区域的端点
对于在矩形草坪上圆形的覆盖范围,可以将其转化为一维直线(草坪中心线 \(center\))上的区间覆盖问题。
观察到圆形范围在矩形草坪中覆盖的图形有两种情况:当圆形半径 \(r > \frac{W}{2}\) 时,图形为两边有弧度的矩形;当 \(r \le \frac{W}{2}\) 时,图形为完整的圆形(如图灰色部分)。
对于第一种情况,实际起到作用的是下图灰色矩形代表的区间。在读入时可以预处理它的左右两个边界,即蓝色边框的位置。具体地,使用勾股定理计算左右边界:令 \(dis = \sqrt {r^2 - (\frac{w}{2})^2}\),则左边界为 \(p - dis\),右边界为 \(p + dis\),其中 \(p\) 为喷水装置的位置。
类似地,对于第二种情况,实际并没有起到覆盖面积的作用(如图,这部分图形没有起到任何作用)。在读入 \(r \le \frac{W}{2}\) 时应当忽略该喷水装置。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
按照左端点排序
按照左端点从小到大的顺序对 \(d\) 数组排序。
1 2 3 4 5 |
|
贪心选择区间
对于某个未被覆盖到的点 \(p (0\le p < l)\),枚举所有能覆盖到点 \(p\) 的区间,选择其中右端点最大的喷水装置,并将 \(p\) 更新为右端点的坐标,作为下一个未被覆盖的点,继续循环。
其中,枚举所有能覆盖点 \(p\) 的区间,可以从上一次循环枚举到的最后一个区间之后开始。
对于未被覆盖到的点 \(p\),如果没有任何区间能够覆盖它,则无法灌溉,输出 \(-1\)。
如果 \(p\) 超过 \(l\),说明全部覆盖完成,可以输出答案。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
完整代码
Warning
提交到 UVA 上时,涉及到位置的变量建议都定义为浮点型;
Libre OJ 上需要多读入一行多测数据组数 \(T\),而 UVA 不需要。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
|