思想:贪心。设最左边一结点为v,从左开始找一个能包含v而且圆心距离v(v在左,圆心在右)最远的坐标,然后判断此点是否能包含下一节点,如果能,继续判断能否包含下一节点,直至不能包含下一结点。然后再从当前结点开始找一个能包含此结点而且圆心距离它(v在左,圆心在右)最远的坐标,依次类推。
可惜此方法是错误的!试考虑下面数据:
2 3
0 2
1 3
正确结果应当是1,但是用以上方法得出结果为2。
但不无收获,发现自己写的一个QuickSort()函数比stdlib.h中的qsort()要快。
以下是WA代码:
Code
#include <stdio.h>
#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
如果是第二种情况,则必须设置一个雷达在前一个区间;
而第一和第三种情况则不确定是否要设置雷达,需要从第二个区间开始继续考虑。
Code
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <math.h>
4 #define SIZE 1000
5 typedef struct{
6 double l;//l,r首先保存输入点的坐标(x, y),mapping后保存x轴上两坐标
7 double r;
8 }POINT;
9 POINT p[1000];//保存结点坐标以及后来映射到x轴上的两点
10 int d2;//园半径的平方值
11 int cmp(const void *a, const void *b)//qsort的cmp函数
12 {
13 return (((*(POINT *)a).l) >= ((*(POINT *)b).l)) ? 1: -1;
14 }
15 int Greedy(int n)
16 {
17 int i, count;
18 double tail;
19 count=1;
20 tail=p[0].r;
21 for (i=1; i<n; i++){
22 if (p[i].l>tail){
23 count++;
24 tail=p[i].r;
25 }
26 else{
27 if (p[i].r<tail)
28 tail=p[i].r;
29 }
30 }
31 return count;
32 }
33 main()
34 {
35 int c=0, n, d, i, a, x, y, sub;
36 //freopen("input.txt", "r", stdin);
37 while (scanf("%d %d", &n, &d) && (n!=0 || d!=0)){
38 a=0;//最少雷达数,初始为0
39 c++;//case序号
40 if (d<=0){//检查1:如果雷达半径<=0
41 a=-1;
42 }
43 d2=d*d;
44 for (i=0; i<n; i++){
45 scanf("%d %d", &x, &y);
46 if (a!=-1 && (sub=(d2-y*y))>=0){
47 p[i].l=x-sqrt(sub);
48 p[i].r=x+sqrt(sub);
49 }
50 else{
51 a=-1;
52 }
53 }
54 if (a!=-1){
55 qsort(p, n, sizeof(POINT), cmp);
56 a=Greedy(n);
57 }
58 printf("Case %d: %d\n", c, a);
59 }
60 }