题意:
在海上有很多的小岛,要建造一些雷达来把所有的小岛都覆盖掉。
雷达只能建造在海岸线上(水平的X轴),且所有雷达的覆盖半径是相同的。
现在问是否可以建造最少的雷达使得所有的小岛都被覆盖。
思路:
首先可以知道,如果一个小岛的纵坐标大于给定的半径,那么就不会存在合理的方案;
对于一个小岛,可以通过半径计算出雷达的范围,每一个小岛就对应一个雷达的区间,之后就转化成了在X轴上找最少的点,使得所有的区间都被覆盖,又是经典的区间覆盖问题。
要注意的一点是要把重复的小岛去掉,我用的是set解决的这个问题。
对于所有的区间,按照右端点从小到大排序,如果右端点相同,那么按照左端点从小到大排序。之后从第一个区间(当前区间)开始,找到左端点小于等于当前区间的右端点的区间,这些区间都可被当前区间中的某个点覆盖;直到找到左端点大于当前区间的右端点,那么就把这个区间作为当前区间,答案加一,继续找。
代码:
1 #include <stdio.h> 2 #include <set> 3 #include <algorithm> 4 #include <vector> 5 #include <math.h> 6 using namespace std; 7 8 typedef pair<int,int> p; 9 10 set<p> s; 11 vector<p> g; 12 13 const double eps = 1e-8; 14 const int N = 1005; 15 pair<double,double> a[N]; 16 17 bool cmp(pair<double,double> xx,pair<double,double> yy) 18 { 19 if (fabs(xx.second - yy.second) < eps) return xx.first < yy.first; 20 return xx.second < yy.second; 21 } 22 23 int main() 24 { 25 int n,d; 26 int kase = 0; 27 28 while (scanf("%d%d",&n,&d) != EOF && n + d) 29 { 30 s.clear(); 31 g.clear(); 32 33 bool f = 0; 34 35 for (int i = 0;i < n;i++) 36 { 37 int x,y; 38 39 scanf("%d%d",&x,&y); 40 41 s.insert(p(x,y)); 42 43 if (y > d) f = 1; 44 } 45 46 if (f) 47 { 48 printf("Case %d: -1 ",++kase); 49 continue; 50 } 51 52 set<p>::iterator it; 53 54 for (it = s.begin();it != s.end();++it) 55 { 56 g.push_back(*it); 57 } 58 59 int sz = g.size(); 60 61 for (int i = 0;i < sz;i++) 62 { 63 int x = g[i].first,y = g[i].second; 64 65 a[i].first = 1.0 * x - sqrt(1.0 * d * d - 1.0 * y * y); 66 a[i].second = 1.0 * x + sqrt(1.0 * d * d - 1.0 * y * y); 67 } 68 69 sort(a,a+sz,cmp); 70 71 int ans = 1; 72 73 //double dis = (a[0].second - a[0].first) / 2.0; 74 double cur = a[0].second; 75 76 for (int i = 1;i < sz;i++) 77 { 78 if (cur >= a[i].first) continue; 79 else 80 { 81 ans++; 82 cur = a[i].second; 83 } 84 } 85 86 printf("Case %d: %d ",++kase,ans); 87 } 88 89 return 0; 90 }