【poj】1328 Radar Installation 快排+贪婪

先说下我刚开始错误的想法:本想用与一般人不一样的方法,即按岛屿的y坐标递减排列(y相等就按X递增排列),然后每次都先找到y最大的岛屿,并将雷达的x坐标和该岛屿的x坐标一样,
这样雷达就可以侦测更大范围,从island[0]开始枚举找这个属于最大范围的岛屿并把x,y都标记为-1.依次找到把所有的岛屿x,y都标记为-1后输出雷达数.
看似没问题的想法,提交就WA.而且是过了别人给的N组数据.
没办法,自己生成随机数和正确程序对拍,发现死在了一组数据中.觉得这个方法确实有问题.想到了LRJ上面的一个区间选点问题,类似的贪心算法。
正解思路:
    相对原点而言,我们假定x负半周方向为“左”,x正半轴方向为“右”。 
    我们找一个岛屿能被侦测到的极限范围,在雷达侦测区(圆)的左半圆上或者在雷达侦测区(圆)的右半圆上,换句话说当岛屿到雷达的距离等于d时,
    雷达可以位于岛屿的左侧也可以位于雷达的右侧。而这就可以分别确定雷达相对与岛屿x的最左坐标和x最右坐标。
    最左为:x - sqrt(d*d-y*y); 最右为:x - sqrt(d*d-y*y); 
    每个岛屿都有这样的最左和最右可被侦测坐标。
    根据贪婪的思想,每次都应该将最右可被侦测坐标作为衡量标准。
    假定当前的岛屿为cur,当前的下一个为next。
      1.如果next的最左可被侦测坐标比cur的最右都大的话,只能再设一个雷达来侦测next了。
      2.如果next的最左可被侦测坐标比cur的最右小,这时会有两种情况。
          A.next最右 < cur最右
         B.next最右 >= cur最右
         对于B情况,我们可以直接侦测到next了, 可以找next的next了.
         对于A情况,也就等价于next包含于cur, 这样就应该把next的右最为衡量标准了.
        因为这样可以左移最右坐标, 可以让可能更多的岛屿被侦测到(他们的最左与衡量标准有更多的交集)
        具体实现看代码 


点击(此处)折叠或打开

  1. #include <math.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>

  4. #define MAX 1001

  5. typedef struct
  6. {
  7.     double xl; //最左可被侦测坐标
  8.     double xr; //最右可被侦测坐标
  9. }coordinate;

  10. coordinate island[MAX]={0};

  11. //按xl递减排序
  12. int cmp(const void* a, const void *b)
  13. {
  14.     return ((coordinate *)a)->xl > ((coordinate *)b)->xl ? 1 : -1;
  15. }

  16. /******************************************************
  17. |func: 贪婪算法找最少雷达数
  18. |args: 岛屿可被侦测坐标island,岛屿数n,雷达侦测半径d
  19. |retn: 可侦测所有岛屿的最少雷达数
  20. ******************************************************/
  21. int Greedy(coordinate island[], int n, int d)
  22. {
  23.     int num = 0, i;
  24.     double cur; //当前最右可被侦测坐标
  25.     
  26.     cur = island[0].xr;
  27.     num++;
  28.     
  29.     for (i=1; i<n; i++)
  30.     {
  31.         if (island[i].xl - cur > 1e-5) //下个岛屿的最左坐标大于当前最右可被侦测坐标
  32.         {
  33.             num++;
  34.             cur = island[i].xr;
  35.         }
  36.         else
  37.         {
  38.             if (island[i].xr - cur < 1e-5) //下个岛屿的最右坐标小于当前最右可被侦测坐标
  39.             {
  40.                 cur = island[i].xr;
  41.             }
  42.         }
  43.     }
  44.     return num;
  45. }

  46. int main()
  47. {
  48.     int i, n, d, x, y, count = 0, flag = 0;
  49.     double offset;
  50.     
  51.     while(scanf("%d %d", &n, &d) == 2 && !(n==d && 0==d))
  52.     {
  53.         flag = 0;
  54.         count++;
  55.         
  56.         for (i=0; i<n; i++)
  57.         {
  58.             scanf("%d %d", &x, &y);
  59.             if (y > d)
  60.             {
  61.                 flag = 1;
  62.             }
  63.             offset = sqrt((double)(d * d - y * y));
  64.             island[i].xl = x - offset;
  65.             island[i].xr = x + offset;
  66.         }
  67.         if (flag)
  68.         {
  69.             printf("Case %d: -1n", count);
  70.             continue;
  71.         }
  72.         
  73.         qsort(island, n, sizeof(island[0]), cmp);
  74.         i = Greedy(island, n, d);
  75.         printf("Case %d: %dn", count, i);
  76.     }
  77.     return 0;
  78. }
Problem: 1328  User: angrad 
      Memory: 156K  Time: 0MS 
      Language: C  Result: Accepted


 

转载地址:http://blog.chinaunix.net/uid-22609852-id-3506134.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值