噴水裝置(二)
時間限制:3000 ms | 內存限制:65535 KB
難度:4
- 描述
- 有一塊草坪,橫向長w,縱向長爲h,在它的橫向中心線上不同位置處裝有n(n<=10000)個點狀的噴水裝置,每個噴水裝置i噴水的效果是讓以它爲中心半徑爲Ri的圓都被潤溼。請在給出的噴水裝置中選擇儘量少的噴水裝置,把整個草坪全部潤溼。
- 輸入
- 第一行輸入一個正整數N表示共有n次測試數據。
每一組測試數據的第一行有三個整數n,w,h,n表示共有n個噴水裝置,w表示草坪的橫向長度,h表示草坪的縱向長度。
隨後的n行,都有兩個整數xi和ri,xi表示第i個噴水裝置的的橫座標(最左邊爲0),ri表示該噴水裝置能覆蓋的圓的半徑。 - 輸出
- 每組測試數據輸出一個正整數,表示共需要多少個噴水裝置,每個輸出單獨佔一行。
如果不存在一種能夠把整個草坪溼潤的方案,請輸出0。 - 樣例輸入
-
2
2 8 6
1 1
4 5
2 10 6
4 5
6 5
- 樣例輸出
-
1
2
以爲是個dp,原來是個貪心,維護一個相對於當前位置能夠向右覆蓋的最大距離,依次更新即可
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn = 1e5+10;
struct node{
double s, e;
}rec[maxn];
bool cmp(const node& a, const node& b){
return a.s < b.s;
}
int main(){
int t, n, v, ans;
double w, h, cur;
scanf("%d", &t);
while(t--){
scanf("%d%lf%lf", &n, &w, &h);
h /= 2;
cur = v = ans = 0;
for(int i = 0; i < n; i++){
double a, b;
scanf("%lf%lf", &a, &b);
if(b <= h) continue;
rec[v].s = a-sqrt(b*b-h*h);
rec[v++].e = a+sqrt(b*b-h*h);
}
sort(rec, rec+v, cmp);
bool flag = false;
while(cur < w){
double Max = 0;
for(int i = 0; i < v && rec[i].s <= cur; i++){//cur是當前位置,Max是最大的相對向右覆蓋距離
if(Max < rec[i].e - cur) Max = rec[i].e - cur;
}
if(Max == 0){//若覆蓋不到最右端,肯定會有無法更新的時候,即Max爲0,可以作爲終止條件
flag = true;
break;
}
cur += Max;
ans++;
}
printf("%d\n", flag ? 0 : ans);
}
return 0;
}