这道题我们看上去没有思路。但是当我们知道了岛屿的位置和雷达的扫描半径后,我们就可以求出要扫描到每个岛屿,雷达的安装范围。同时,根据贪心原理,很明显要把雷达尽量布置在海岸线上。这样,我们就将本题转化为了一道区间选点问题,只需要选择尽量少的点,满足每一个扫描区间内都有一个点即可。
下面分析代码。
首先,我们还是要先定义好岛屿个数n和雷达的扫描半径d,并设置一个cnt来记录最少的雷达数。
同时,我们来定义一个结构体来记录每一个岛屿所对应的雷达扫描区间。设置两个double变量l和r来标记边界。得到代码如下:
1 #include
2 using namespace std;
3 int n,d,ans;
4 struct qujian{
5 double l,r;
6 }t[1005];
7 int main(){
8 return 0;
9 }
接下来,我们要进行读入。先读入岛屿树木n和雷达扫描半径d,然后从1到n依次读入每个岛屿的坐标。因为读入的并不是区间的左边界和右边界,所以我定义了两个整型变量a,b表示坐标(因为将该坐标转化为区间后,该坐标不再有作用,所以可以直接覆盖)。如果b>d,说明无论如何雷达也扫描不到该岛屿,则需要输出-1,并且直接return 0。否则,我们可以根据两点间距离公式得出区间的左边界l=a-sqrt(d*d-b*b);右边界r=a+sqrt(d*d-b*b)。得到代码如下:
1 #include
2 using namespace std;
3 int n,d,ans,a,b;
4 double position;
5 struct qujian{
6 double l,r;
7 }t[1005];
8 int main(){
9 cin>>n>>d;
10 for(i=1;i<=n;i++){
11 cin>>a>>b;
12 if(b>d){
13 cout<<-1<<endl;
14 return 0;
15 }
16 t[i].l=a-sqrt(d*d-b*b);
17 t[i].r=a+sqrt(d*d-b*b);
18 }
19 return 0;
20 }
接下来,我们便可以使用区间选点问题的处理方法进行计算。
首先,我们仍需要按照区间的右边界进行排序。这里仍然使用
下一步,我们要枚举每一个区间。注意这里和一般的区间选点问题不同的是,区间的边界和雷达的安装都是double类型的,而且每个区间固定只需要安装一个点。所以我们只需要定义一个double类型的变量position,来记录当前的最靠右的雷达位置。
这里需要注意的是,在枚举每个岛屿时,第一个岛屿并不是从0点开始的,所以在初始化时,我们需要将r初始化为第一个节点的右边界,而非0,同时将ans初始化为1(默认第一个雷达安装在第一个岛屿右边界),并从2开始枚举安装雷达。
下面是本题的完整代码:
1 #include2 #include 36 return 0; 37 }3 #include 4 using namespace std; 5 int n,d,ans,a,b,i; 6 double position; 7 struct qujian{ 8 double l,r; 9 }t[1005]; 10 double cmp(qujian a,qujian b){ 11 return a.r<b.r; 12 } 13 int main(){ 14 cin>>n>>d; 15 for(i=1;i<=n;i++){ 16 cin>>a>>b; 17 if(b>d){ 18 cout<<-1<<endl; 19 return 0; 20 } 21 t[i].l=a-sqrt(d*d-b*b); 22 t[i].r=a+sqrt(d*d-b*b); 23 } 24 sort(t+1,t+n+1,cmp); 25 ans=1; 26 position=t[1].r; 27 for(i=2;i<=n;i++){ 28 if(position>=t[i].l){ 29 continue; 30 }else{ 31 ans++; 32 position=t[i].r; 33 } 34 } 35 cout< endl;