1801: 噴水裝置(二)
題目描述
有一塊草坪,橫向長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
沒什麼好說的 只要根據噴水裝置的噴水半徑和草坪寬度算出在橫向上最多能完全覆蓋的座標就是轉化成了最少線段完全覆蓋問題,上代碼
#include<iostream>
#include<memory.h>
#include<cmath>
#include<algorithm>
using namespace std;
struct Node {
int x, R;
double l, r; //噴水裝置覆蓋的左右極限座標
} a[10000];
bool cmp ( Node a, Node b ) {
if ( a.l != b.l ) {
return a.l < b.l;
}
else return a.r < b.r;
}
int main ( ) {
int N, n, w, h, i;
scanf ( "%d", &N );
while ( N -- ) {
memset ( a, 0, 10000 * sizeof ( Node ) );
scanf ( "%d %d %d", &n, &w, &h );
for ( i = 0; i < n; i ++ ) {
scanf ( "%d %d", &a[i].x, &a[i].R );
if ( 2 * a[i].R <= h ) {
a[i].l = 0;
a[i].r = 0;
}
else { //計算左右覆蓋極限
double m = pow ( a[i].R, 2 ) - pow ( ( double ) h / 2, 2 );
a[i].l = a[i].x - sqrt ( m );
a[i].r = a[i].x + sqrt ( m );
}
}
sort ( a, a + n, cmp ); //左極限升序排列
int cr = 0, r = 0, k = 0, j;
for ( i = 0; i < n && w > 0; i ++ ) {
for ( j = i; j < n; j ++ ) { //在符合條件的噴水裝置中選擇右極限最大的
if ( a[j].l <= r && a[j].r > r && a[j].r > cr ) {
cr = a[j].r;
i = j;
}
}
if ( a[i].l <= r && cr != 0 ) {
w -= cr - r;
r = cr;
k ++;
cr = 0;
}
}
if ( w > 0 ) {
printf ( "0\n" );
}
else printf ( "%d\n", k );
}
return 0;
}