1424:【例題3】噴水裝置
時間限制: 1000 ms 內存限制: 65536 KB
提交數: 2916 通過數: 572
【題目描述】
長 L 米,寬 W 米的草坪裏裝有 n 個澆灌噴頭。每個噴頭都裝在草坪中心線上(離兩邊各 W2 米)。我們知道每個噴頭的位置(離草坪中心線左端的距離),以及它能覆蓋到的澆灌範圍。
請問:如果要同時澆灌整塊草坪,最少需要打開多少個噴頭?
【輸入】
輸入包含若干組測試數據。
第一行一個整數 T 表示數據組數;
每組數據的第一行是整數 n、L 和 W;
接下來的 n 行,每行包含兩個整數,給出一個噴頭的位置和澆灌半徑(上面的示意圖是樣例輸入第一組數據所描述的情況)。
【輸出】
對每組測試數據輸出一個數字,表示要澆灌整塊草坪所需噴頭數目的最小值。如果所有噴頭都打開也不能澆灌整塊草坪,則輸出 −1 。
【輸入樣例】
3
8 20 2
5 3
4 1
1 2
7 2
10 2
13 3
16 2
19 4
3 10 1
3 5
9 3
6 1
3 10 1
5 3
1 1
9 1
【輸出樣例】
6
2
-1
【提示】
數據範圍:
對於 100% 的數據,n≤15000。
思路:本題用貪心算法來解,結構體存每個噴頭的前後到達位置;以前端位置排序;
一個個掃描可以到達之前的後端,並且自己可以到達最遠的後端;分析不成立的情況;
由於曲線不好處理,所以我們可以將覆蓋面積近似的看成是圖中紅色矩形覆蓋的面積(這樣對結果不造成影響)那麼這個矩陣的左端點與大區間最左側的距離爲 x - √[r^ 2-(h/2) ^ 2],矩形的右端點與大區間最左側的距離爲x + √[r^ 2 - (h/2)^2];
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cmath>
using namespace std;
int n,cnt,L,h,x,r;
struct node{
double x;
double y;
}a[20005];
bool cmp(node a, node b){
return a.x < b.x;
}
void read(){
cin >> n >> L >> h;
cnt = 0;
for(int i = 1; i <= n; i++)
{
cin >> x >> r;
if(r <= h/2) continue; //cnt是有用的裝置的個數,條件爲r>h/2
cnt++;
a[cnt].x = x - sqrt(r*r - h*h/4.0);
a[cnt].y = x + sqrt(r*r - h*h/4.0);
}
}
void solve(){
double t = 0;
int ans = 0,flag1 = 1, i = 1;
while(t < L){
ans++;
double s = t;
for(;a[i].x <= s&&i <= cnt;i++)//依次找到覆蓋l的最大右端
if(t < a[i].y)
t = a[i].y;
if(t == s && s <L)
{
cout << -1 << endl;
flag1 = 0;
break;
}
}
if(flag1) cout << ans << endl;
}
int main(){
int T;
cin >> T;
while(T--){
read();
sort(a+1,a+1+cnt,cmp);
solve();
}
return 0;
}