POJ 1089【Intervals】題目連結:
思路
我們可以使得每個雷達儘可能多的覆蓋小島。我們可以列舉每個小島求出能覆蓋當前小島的雷達放置位置的區間,從左往右看,為了儘量不浪費雷達的檢測範圍,對於第一個雷達,為了不浪費雷達的檢測範圍,所以將第一個雷達放在第一個放置區間的最右端,然後依次列舉下一個小島,取前兩個小島的放置區間的交集,直到出現第一個小島的放置區間不在當前交集區間內,則新增雷達。所以此時根據性質,可以將放置區間按區間右端點排序,則不需要對區間進行單獨討論了,只需要確定一個右端點為依次遍歷直到找出第一個放置區間左端點大於交集區間右端點的小島,此時則將交集區間更新為這個小島的放置區間,即為新放置一個雷達,依次列舉遍歷所有的小島。
程式碼
#include <iostream>
#include <algorithm>
#include <math.h>
using namespace std;
#define ll long long
const int N = 1e5 + 10;
ll n, m, flag;
pair<double , double> site[N];
pair<double, double> segment[N];
bool cmp(pair<double, double> a, pair<double, double> b) { return a.second < b.second; }
int main() {
ll t = 0;
while (cin >> n >> m) {
t++;
flag = 0;
if (n == 0 && m == 0) {
break;
}
for (int i = 1; i <= n; i++) {
cin >> site[i].first >> site[i].second;
if (site[i].second > m) {
flag = 1;
}
}
if (flag) {
cout << "Case " << t << ": -1" << endl;
continue;
}
for (int i = 1; i <= n; i++) {
// 找出線段半徑
double x = sqrt((double)m * (double)m - (double)site[i].second * (double)site[i].second);
segment[i].first = site[i].first - x, segment[i].second = site[i].first + x;
}
sort(segment + 1, segment + 1 + n, cmp);
int num = 1;
double r = segment[1].second;
for (int i = 2; i <= n; i++) {
if (r < segment[i].first) {
r = segment[i].second;
num++;
}
}
cout << "Case " << t << ": " << num << endl;
}
return 0;
}