解题报告 Sadar

 

1.        题目

3.Sadar             

题目描述:

假设海岸线是一条直线,大海在海岸线的一侧(纵坐标为非负),每个小岛都是海中的一个点,现在在海岸线上安装雷达,所安装的雷达型号相同,即每个雷达所能检测到的范围都是等大的(雷达的检测范围是半径为d的圆)。已知雷达只能建在海岸线上,现在给你n个岛的坐标,假设海岸线为坐标系的x轴,求出最少要建造多少个雷达才能监测到所有的小岛(每个小岛可以被多个雷达监测)。

输入:

  输入多组数据。

对于每组数据,第一行输入两个正整数n,d ,分别代表小岛的个数和雷达监测的半径

接下来有n行,每行两个整数x,y  代表小岛的横纵坐标

输出:

  对于每组数据,输出最小所需的雷达数,若无法覆盖所有的小岛,输出-1

数据范围:

  n<=1000

  -maxlongint<=x<=maxlongint

样例:

输入:

3 2

1 2

-3 1

2 1

1 2

0 2

输出:

2

1

 

2.        题目实质

还记得那个点覆盖区间的贪心不?

3.        算法

贪心。

首先,预处理一下,计算出包含这个点的圆的圆心在哪个区间里,则圆心在这个区间里的圆一定可以包含这个点,这样就转换成了,选取最少的点,使每个区间里都至少有一个点。(如果一个点只能包含一次,那就只能用动规了)

然后关于这个经典模型,这里提供三种解法:

       按终点排序,从小到大,选取每一个没有点的区间的右端点(易证,右端点最易在下一个区间内)。

       按起点倒序排序,从大到小,选取每一个没有点的区间的右端点。

       按起点排序,当一个区间包含另一个区间时,将比较大的那个区间的 y 值赋为较小的区间的 y 值(易证,如果一个点在一个较小的区间里,且一个较大的区间包含这个较小的区间,则这个点一定在那个较大的区间里)。然后再依次选取每个区间的右端点,当后一个区间与前一个区间不包含也不交叉时,将答案加一。

以上三种方法,都是为了避免区间相互包含的情况。

然后就是这样。

4.        注意事项

这个题不是计算几何。

其实,比较难的动规题,是可以用贪心骗分的。

5.        程序代码

Leve  第三种贪心 Pascal

var

 x,y:array[1..1000] of double;

 n,i,j,d,ans,max,xxx,yyy:longint;

 tou:double;

procedure qs(r,l:longint);

 var

  i,j:longint;

  xx,yy :double;

 begin

  i:=r; j:=l;

  xx:=x[(i+j)>>1];

  repeat

   while x[i]<xx do inc(i);

   while x[j]>xx do dec(j);

   if i<=j then

    begin

        yy:=x[i]; x[i]:=x[j]; x[j]:=yy;

        yy:=y[i]; y[i]:=y[j]; y[j]:=yy;

         inc(i);

        dec(j);

       end;

   until i>j;

 if i<l then qs(i,l);

 if j>r then qs(r,j);

end;

begin

 assign(input,'radar.in');

 assign(output,'radar.out');

 reset(input);

 rewrite(output);

  readln(n,d);

 while (n<>0) and (d<>0) do

 begin

 max:=0;

 for i:=1 to n do

  begin

  readln(xxx,yyy);

  if yyy>max then max:=yyy;

  if yyy>d then

  begin

   for j:=i+1 to n do

    readln(xxx,yyy);

    break;

   end;

  x[i]:=xxx-sqrt(sqr(d)-sqr(yyy));

  y[i]:=xxx+sqrt(sqr(d)-sqr(yyy));

  end;

 if max>d then

 begin

  writeln('-1');

 end

 else

 begin

 ans:=1;

 qs(1,n);

 tou:=y[1];

 for i:=2 to n do

  if y[i]<tou then

   begin

    tou:=y[i];

 

   end

  else

   if x[i]>tou then

   begin

   tou:=y[i];

   inc(ans);

   end;

writeln(ans);

end;

 

readln(n,d);

end;

 close(input);

 close(output);

end.

 

 

 

 

 

原文地址:https://www.cnblogs.com/SueMiller/p/2135164.html