噴水裝置(二)
時間限制: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
區間覆蓋問題分成三種情況(“---”表示區間)
第一種情況
a -----------
b --------------
c -----------
此時沒有能覆蓋b和c之間的區域
第二種情況
a -----------
b ------------
c -------------
此時需要選擇a,b,c三個區間
第三種
a -----------
b -------------
c ---------------此時選擇a,c兩個區間就能覆蓋住,不需要選擇3個區間
#include <iostream> #include <vector> #include <algorithm> #include <cmath> using namespace std; struct Segment{ double first,second; Segment(double first_ = 0, double second_ = 0):first(first_),second(second_){} bool operator < (const Segment& a) const{ if(first!=a.first) return first < a.first; else return second > a.second; } }; int main(){ int N; cin >>N; for(int icase = 0 ; icase < N; icase ++ ){ int n; double w,h; cin >> n >>w >> h; vector<Segment> segments; for(int i = 0 ; i < n; ++ i){ double x,r; cin >> x >>r; if(2*r >= h){ segments.push_back(Segment(x - sqrt(4*r*r-h*h)/2,x + sqrt(4*r*r-h*h)/2)); } } sort(segments.begin(),segments.end()); int cnt = 1; double left = segments[0].first, right = segments[0].second, prevRight = 0; for(int i = 1 ; i < segments.size(); ++ i){ if(segments[i].first > right ){ // 第一種情況 cnt = 0; break; }else if(segments[i].first >= prevRight){ //第二種情況 cnt++; prevRight = right; right = segments[i].second; }else if(segments[i].first < prevRight && segments[i].second > right){ //第三種情況 right = segments[i].second; } if(right >= w) break; } if(left<= 0 && right >= w) cout<<cnt<<endl; else cout<<0<<endl; } }