Uva 10382 Watering Grass
题意:给一个长宽:l*w的矩形,然后在w/2这条线上有n个点,以这些点为圆心,ri为半径,选择尽量少的点,覆盖这个矩形
题解:不能只有用圆去求,应当把每个圆转化成矩形去求,即转化为区间覆盖问题
1.把每个圆转化为小矩形,然后求出左右端点
2.以左端点和右端点排序
3.贪心循环去找
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define db double 4 struct st{ 5 db p,r; 6 db left, right; 7 }; 8 st a[10000+20]; 9 bool cmp(st a, st b) 10 { 11 if(a.left!=b.left) return a.left<b.left; 12 return a.right<b.right; 13 } 14 int main() 15 { 16 int n; 17 ios::sync_with_stdio(false); 18 db l,w; 19 while(cin >> n >> l >> w) 20 { 21 int j = 0; 22 for(int i = 0;i < n;i++) 23 { 24 db x,y; 25 cin >> x >> y; 26 if(w>2*y) continue; 27 a[j].p = x; a[j].r = y; 28 a[j].left = x - sqrt( y*y - ((w/2)*(w/2)) ); 29 if(a[j].left<0) a[j].left=0; 30 a[j].right = x + sqrt( y*y - ((w/2)*(w/2)) ); 31 if(a[j].right>l) a[j].right=l; 32 j++; 33 } 34 int m = j; 35 sort(a,a+m,cmp); 36 if(a[0].left>0) {cout << "-1" << endl;continue;} //如果最左端点都不能覆盖0 37 db mx = a[0].right; 38 int i = 1; 39 while(a[i].left == 0)i++; //找到覆盖0并且右端点最远的 40 mx = a[i-1].right; 41 int ans=1; 42 while(1) 43 { 44 if(i>=m||mx==l) break; //m个点,或者覆盖了l,退出while 45 db pp = mx; 46 int flag=0,f=0; 47 while(a[i].left<=pp) //找每一个左端点在上一个点最右端的里面的所有点 48 { f=1; 49 if(a[i].right>mx){ 50 mx = a[i].right; //更新mx 51 flag=1; 52 } 53 i++; 54 if(i>=m||mx==l) break; 55 } 56 if(flag) ans++; //如果更新了,则多了一个点 57 if(f==0) i++;//防死循环 58 } 59 if(mx==l) cout << ans << endl; 60 else cout << "-1" << endl; 61 } 62 }
浙公网安备 33010602011771号