NYACM_006
题目:喷水装置(一)
链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=6
描述:
描述
现有一块草坪,长为20米,宽为2米,要在横中心线上放置半径为Ri的喷水装置,每个喷水装置的效果都会
让以它为中心的半径为实数Ri (0 < Ri<15)的圆被湿润,这有充足的喷水装置i(1< i<600)个,并且一定能把草坪全部湿润,你要做的是:选择尽量少的喷水装置,把整个草坪的全部湿润。
输入
第一行m表示有m组测试数据
每一组测试数据的第一行有一个整数数n,n表示共有n个喷水装置,随后的一行,有n个实数ri,ri表示该喷水装置能覆盖的圆的半径。
输出
输出所用装置的个数
样例输入
2
5
2 3.2 4 4.5 6
10
1 2 3 1 2 1.2 3 1.1 1 2
样例输出
2
5
分析:
想要喷水装置最少,采用贪心算法,总是选择当前可用最大的,覆盖尽可能多的范围。不过贪心算法存在缺点,即不是最优解,先试试看能不能AC。
只是试一试而已,居然直接AC了,考虑到未必能够充分利用到所能用到的最大面积,比如剩余若干个小块虽然总面积小于下一个最大块覆盖面积,但是由于分布不同位置,一块可能不够,类似华容道那样,不过难度只有3,可能没有这种特殊的测试数据,当然也可能是自己想多了。
AC Code
/*
贪心算法求解NYACM_006
*/
#include <vector> //使用vector存储,直接利用sort排序,方便从大到小选择使用
#include <algorithm>
#include <iostream>
#include <cmath>
using namespace std;
double GetLeftArea(double LeftArea, double size)
{
double ret;
double area;
if (fabs(size - 2) <= 1e-9)
{
area= 2 * size*size;
}
else
{
area= sqrt(size*size - 1) * 4;
}
//cout << "use " << size << " area is " << area << endl;
ret= LeftArea - area;
if (ret < 0)
{
ret = 0;
}
return ret;
}
int main()
{
int m; //M组测试数据
cin >> m;
while (m--)
{
int n; //n个装置
cin >> n;
vector<double> Devices;
int counter=0;
for (int i = 0; i < n; i++)
{
double tmp; //喷水范围实数
cin >> tmp;
Devices.push_back(tmp);
}
sort(Devices.begin(), Devices.end());
//草坪长20,宽2,喷水范围Ri [0,15],整个草坪湿润相当于覆盖整个草坪
//每个喷水装置覆盖的面积范围:
//如果Ri<=1,即整个圆都在草坪内,但是要求覆盖全部,取最大面积内接正方形 2*Ri*Ri
//如果Ri>1,即有在草坪外部分,圆心在中轴线上能覆盖最大面积,此时最大面积为 sqrt(Ri*Ri-1)*2*2
//覆盖整个面积2*20
//实际摆放应该更复杂,要考虑形状等,暂且这样编程,看能否通过
double leftArea = 40;
for (int i = Devices.size() - 1; i >= 0; i--)
{
counter++;
//cout << "now use " << Devices[i] << endl;
leftArea = GetLeftArea(leftArea, Devices[i]);
//cout << "now leftArea is " << leftArea << endl;
if (fabs(leftArea) < 1e-9 )
{
break;
}
}
cout << counter << endl;
}
}
其他:
提交后会自动跳转到运行结果,上面AC code时间/内存是4/312,看到下面有0/236的,可能采用了更高效的做法吧,不过从头过一遍各个题的目的是扩展视野,以后不太可能参加ACM比赛了,暂且这样吧,以后再尝试降低时间/内存。