思想:贪心。设最左边一结点为v,从左开始找一个能包含v而且圆心距离v(v在左,圆心在右)最远的坐标,然后判断此点是否能包含下一节点,如果能,继续判断能否包含下一节点,直至不能包含下一结点。然后再从当前结点开始找一个能包含此结点而且圆心距离它(v在左,圆心在右)最远的坐标,依次类推。
可惜此方法是错误的!试考虑下面数据:
2 3
0 2
1 3
正确结果应当是1,但是用以上方法得出结果为2。
但不无收获,发现自己写的一个QuickSort()函数比stdlib.h中的qsort()要快。
以下是WA代码:
#include <math.h>
#define MAX 1000
#define PI 3.1415926
int ildX[MAX];
int ildY[MAX];
int n;
int d;
void Swap(int a, int b)
{
int t;
t=ildX[a];
ildX[a]=ildX[b];
ildX[b]=t;
t=ildY[a];
ildY[a]=ildY[b];
ildY[b]=t;
}
void QuickSort(int low, int high)
{
int pivot, i, j;
if (low>=high)
return;
i=low+1;
j=high;
pivot=ildX[low];
while (i<=j){
while ((ildX[i]<=pivot) && (i<=high)) i++;
while ((ildX[j]>pivot) && (j>=low)) j--;
if (i<j && ildX[i]>ildX[j]) Swap(i, j);
}
if (low < j) Swap(low, j);
QuickSort(low, j-1);
QuickSort(j+1, high);
}
int Greedy()
{
int d2, i, x, count;
count=0;
d2=d*d;
for (i=0; i<n; ){
count++;
x=(int)sqrt((double)(d2-ildY[i]*ildY[i]))+ildX[i];
i++;
while ((d2 >= (( x-ildX[i])*(x-ildX[i]) + ildY[i]*ildY[i] )) && i<n){
i++;
}
}
if (count==0)
return -1;
return count;
}
main(int argc, char *argv[])
{
int i, a, c=0;
freopen("input.txt", "r", stdin);
while (scanf("%d %d", &n, &d) && (n!=0 && d!=0)){
c++;
for (i=0; i<n; i++){
scanf("%d %d", ildX+i, ildY+i);
}
QuickSort(0, n-1);
a=Greedy();
printf("Case %d: %d\n", c, a);
}
}
经过五六次WA,终于AC了。
参考了高手的思想:将问题转化为区间,然后从中找出能覆盖所有区间的最少点数目。
考虑区间直线的最优子结构:如果只有两条相邻直线,那么会出现三种情况:
1. ————
————
---------------------------------------
2. ————
————
----------------------------------------
3. ——————
————
----------------------------------------
即1:p[i].l <= p[i+1].l && p[i].r<p[i+1].r
2:p[i].r <= p[i+1].l
3:p[i].l <= p[i+1].l && p[i].r>=p[i+1].r
如果是第二种情况,则必须设置一个雷达在前一个区间;
而第一和第三种情况则不确定是否要设置雷达,需要从第二个区间开始继续考虑。