zoukankan      html  css  js  c++  java
  • Greedy:Radar Installation(POJ 1328)

              

                装雷达

      题目大意,就是令在海岸线的(直线)一边是海(y>0),另一边是陆地(y<=0),在海岸线上装雷达,雷达可以覆盖的范围为d,海上有岛,(x,y),问你应该怎么装雷达,才能做到技能雷达的检测范围覆盖全部的岛,又能使雷达安装最少?(不能做到输出-1)

      我的思路,首先是把岛排一次序,然后从x坐标最小的那个岛开始贪心算法,怎么做呢?那就是用x=sqrt(d*d-y*y)+xa,来获得当前岛的安装最远的雷达的位置,然后不断往前找,在超越当前雷达圆心距离之前,不断缩小雷达的位置,使雷达能覆盖到更多的岛,直到岛的横坐标超出雷达中心。

      接下来把当前的雷达中心为圆心,把覆盖在圆内的岛全部找出来,这能使一个雷达能覆盖岛最多,然后从最靠近雷达的第一个没被覆盖的岛开始,重复上述过程。

      

      1 #include <iostream>
      2 #include <functional>
      3 #include <algorithm>
      4 #include <math.h>
      5 
      6 using namespace std;
      7 typedef double Position;
      8 typedef struct coordinate
      9 {
     10     Position x;
     11     Position y;
     12 }Pos;
     13 int fcmop(const void* a, const void *b)
     14 {
     15     return (*(Pos *)a).x > (*(Pos *)b).x ? 1 : -1;
     16 }
     17 
     18 static Pos islands[1000];
     19 static bool used[1000];
     20 int Search(const int, const int);
     21 bool Judge(const int,const int);
     22 double dist(Pos, Position);
     23 Position get_radar_pos(Pos, const int);
     24 
     25 int main(void)
     26 {
     27     int Sum_Of_Islands, Distance_Of_Radar, k = 1, ans;
     28     while (~scanf("%d%d", &Sum_Of_Islands, &Distance_Of_Radar))
     29     {
     30         if (Sum_Of_Islands == 0 && Distance_Of_Radar == 0)
     31             break;
     32         for (int i = 0; i < Sum_Of_Islands; i++)
     33             scanf("%lf%lf", &islands[i].x, &islands[i].y);
     34         qsort(islands, Sum_Of_Islands, sizeof(Pos), fcmop);//把岛都按照顺序排序
     35         memset(used, 0, sizeof(used));
     36         ans = Search(Sum_Of_Islands, Distance_Of_Radar);
     37 
     38         printf("Case %d: %d
    ", k++, ans);
     39     }
     40 
     41     return 0;
     42 }
     43 
     44 double dist(Pos a, Position mid)//计算两点之间的距离
     45 {
     46     return sqrt((a.x - mid)*(a.x - mid) + a.y*a.y);
     47 }
     48 
     49 Position get_radar_pos(Pos a, const int dist)
     50 {
     51     Position k = sqrt((double)(dist*dist) - a.y*a.y) + a.x;
     52     return k;
     53 }
     54 
     55 bool Judge(const int j, const int Distance_Of_Radar)
     56 {
     57     if (islands[j].y - Distance_Of_Radar > 0)//不可能找到一个雷达覆盖这个岛,直接退出
     58         return 1;
     59     else if (islands[j].y < 0)
     60         return 1;
     61     else return 0;
     62 }
     63 
     64 int Search(const int Sum_Of_Islands, const int Distance_Of_Radar)
     65 {
     66     Position tmp_pos, now_min_pos;
     67     int ans = 0, tmp_mid, j, now_is = 0;
     68 
     69     if (Distance_Of_Radar <= 0)//Distance小于0,直接再见
     70         return -1;
     71     for (; now_is < Sum_Of_Islands;)
     72     {
     73         if (Judge(now_is, Distance_Of_Radar)) return -1;
     74         tmp_mid = now_is;
     75         now_min_pos = get_radar_pos(islands[now_is], Distance_Of_Radar);//初始化最远位置
     76         used[now_is] = 1;
     77         for (j = now_is + 1; j < Sum_Of_Islands && islands[j].x <= now_min_pos; j++)
     78         {
     79             if (used[j]) continue;//必须没被标记过
     80             if (Judge(j, Distance_Of_Radar)) return -1;
     81             used[j] = 1;//记得标记
     82             tmp_pos = get_radar_pos(islands[j], Distance_Of_Radar);
     83             if (tmp_pos <= now_min_pos)//必须是不能被覆盖才更新
     84             {
     85                 now_min_pos = tmp_pos;
     86                 tmp_mid = j;//更新是哪一个岛才是中间岛
     87             }
     88         }
     89         ans++;//建立雷达点
     90         for (j = tmp_mid; j < Sum_Of_Islands && islands[j].x <= now_min_pos + Distance_Of_Radar; j++)//把圈内的岛都排除
     91         {
     92             if (Judge(j, Distance_Of_Radar)) return -1;
     93             else if (dist(islands[j], now_min_pos) <= Distance_Of_Radar)
     94                 used[j] = 1;
     95         }
     96         for (j = tmp_mid; j < Sum_Of_Islands && used[j]; j++);//在中心往前找找到第一个没有被标记的点
     97         now_is = j;
     98     }
     99     return ans;
    100 }

      代码的变量命名已经能很清楚说明我在干什么了

      另外其实代码还可以简化一下,那就是去除used域,其实我们在上面找在雷达圆心右方到那些没被覆盖的岛的时候,我们忽略了其实新的圆也可以与当前作用域重复的,那么我们可以就把used区域去掉,然后把代码改成只要找到在半径外,我们就退出循环。(我就不改了)

      另外这一道题其实是挺著名的区间贪婪算法,只是我没有用区间去做而已

      要做也很简答,思路就是以岛为圆心,雷达监控范围为半径,画圆,与x轴会有两个交点,然后不断去掉重复区间就可以了,如果有区间是重复的,我们就不断缩小区间,如果区间没有交集了,我们就添加一个雷达,重复步骤

      详情见:http://www.cnblogs.com/yu-chao/archive/2011/07/18/2109756.html

      另种方法速度差不多,都是O(n)

      最近真的是忙死我了,都没什么时间做题,哎

  • 相关阅读:
    技术干货 | 闲鱼:一个优秀的 Push 平台,需要经历怎样的前世今生
    钉钉宜搭3.0发布!易连接、酷数据、更安全
    聚焦2021云栖大会,边缘云专场畅谈技术应用创新
    基层数字化治理困境如何破局?
    2021年阿里云双11上云狂欢节亿元加油包提前领攻略
    形式化验证工具TLA+:程序员视角的入门之道
    ArrayList源码浅析
    对云信SDK的研究
    写在当下
    Delphi 正则表达式起步
  • 原文地址:https://www.cnblogs.com/Philip-Tell-Truth/p/4875573.html
Copyright © 2011-2022 走看看