先说下我刚开始错误的想法:本想用与一般人不一样的方法,即按岛屿的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的右最为衡量标准了.
因为这样可以左移最右坐标, 可以让可能更多的岛屿被侦测到(他们的最左与衡量标准有更多的交集)
具体实现看代码
点击(此处)折叠或打开
- #include <math.h>
- #include <stdio.h>
- #include <stdlib.h>
-
- #define MAX 1001
-
- typedef struct
- {
- double xl; //最左可被侦测坐标
- double xr; //最右可被侦测坐标
- }coordinate;
-
- coordinate island[MAX]={0};
-
- //按xl递减排序
- int cmp(const void* a, const void *b)
- {
- return ((coordinate *)a)->xl > ((coordinate *)b)->xl ? 1 : -1;
- }
-
- /******************************************************
- |func: 贪婪算法找最少雷达数
- |args: 岛屿可被侦测坐标island,岛屿数n,雷达侦测半径d
- |retn: 可侦测所有岛屿的最少雷达数
- ******************************************************/
- int Greedy(coordinate island[], int n, int d)
- {
- int num = 0, i;
- double cur; //当前最右可被侦测坐标
-
- cur = island[0].xr;
- num++;
-
- for (i=1; i<n; i++)
- {
- if (island[i].xl - cur > 1e-5) //下个岛屿的最左坐标大于当前最右可被侦测坐标
- {
- num++;
- cur = island[i].xr;
- }
- else
- {
- if (island[i].xr - cur < 1e-5) //下个岛屿的最右坐标小于当前最右可被侦测坐标
- {
- cur = island[i].xr;
- }
- }
- }
- return num;
- }
-
- int main()
- {
- int i, n, d, x, y, count = 0, flag = 0;
- double offset;
-
- while(scanf("%d %d", &n, &d) == 2 && !(n==d && 0==d))
- {
- flag = 0;
- count++;
-
- for (i=0; i<n; i++)
- {
- scanf("%d %d", &x, &y);
- if (y > d)
- {
- flag = 1;
- }
- offset = sqrt((double)(d * d - y * y));
- island[i].xl = x - offset;
- island[i].xr = x + offset;
- }
- if (flag)
- {
- printf("Case %d: -1n", count);
- continue;
- }
-
- qsort(island, n, sizeof(island[0]), cmp);
- i = Greedy(island, n, d);
- printf("Case %d: %dn", count, i);
- }
- return 0;
- }
Memory: 156K Time: 0MS
Language: C Result: Accepted
/** \brief poj 1328 greedy
*
* \param date 2014/8/1
* \param state AC
* \return memory 736k time 110ms
*
*/
#include <iostream>
#include <fstream>
#include <cmath>
#include <cstdlib>
#include <cstdio>
using namespace std;
const int MAXN=1001;
typedef struct
{
double xl;//最左可被侦测坐标
double xr;//最右可被侦测坐标
}coordinate;
coordinate island[MAXN]={0};
//按xl递减排序
int cmp(const void* a,const void* b)
{
return ((coordinate *)a)->xl > ((coordinate *)b)->xl ? 1:-1;
}
int Greedy(coordinate island[],int n,int d)
{
int num=0,i;
double cur;//当前最右可被侦测坐标
cur=island[0].xr;
num++;
for (i=1; i<n; i++)
{
if (island[i].xl - cur > 1e-5) //下个岛屿的最左坐标大于当前最右可被侦测坐标
{
num++;
cur = island[i].xr;
}
else
{
if (island[i].xr - cur < 1e-5) //下个岛屿的最右坐标小于当前最右可被侦测坐标
{
cur = island[i].xr;
}
}
}
return num;
}
int main()
{
//cout << "Hello world!" << endl;
//freopen("input.txt","r",stdin);
int n;//the number of island
int d;//the distance of radar
int i,x,y,flag=0;
double offset;
int cases=0;
while(scanf("%d%d",&n,&d)==2)
{
if(n==0 && d==0)break;
flag=0;
cases++;
for(int i=0;i<n;i++)
{
cin>>x>>y;
if(y>d)
{
flag=1;//无解
}
offset = sqrt((double)(d * d - y * y));
island[i].xl = x - offset;
island[i].xr = x + offset;
}
if (flag)
{
printf("Case %d: -1\n", cases);
continue;
}
qsort(island, n, sizeof(island[0]), cmp);
i = Greedy(island, n, d);
printf("Case %d: %d\n", cases, i);
}
return 0;
}