南阳理工学院OJ_12_喷水装置(二)
区间选点中的区间完全覆盖问题;求解思路如下。
1:先根据给出的点的坐标和半径取出其能覆盖的线段范围;假如区间长度8,可选的覆盖线段[2,6],[1,4],[3,6],[3,7],[6,8],[2,4],[3,5]
2将每一个区间按照左端点递增顺序排列,拍完序后为[1,4],[2,4],[2,6],[3,5],[3,6],[3,7],[6,8]
3设置一个变量表示已经覆盖到的区域。再剩下的线段中找出所有左端点小于等于当前已经覆盖到的区域的右端点的线段中,右端点最大的线段在加入,直到已经覆盖全部的区域
4过程:
假设第一步加入[1,4],那么下一步能够选择的有[2,6],[3,5],[3,6],[3,7],由于7最大,所以下一步选择[3,7],最后一步只能选择[6,8],这个时候刚好达到了8退出,所选区间为3
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<string> using namespace std; struct inteval { double l,r; }p[10005]; bool cmp(inteval a,inteval b) { return a.l<b.l; } int main() { int t,n,i; double w,h,x,q; scanf("%d",&t); while(t--) { scanf("%d%lf%lf",&n,&w,&h); h/=2; int j=0; for(i=0;i<n;++i) { scanf("%lf%lf",&x,&q); if(q>h) { p[j].l=x-sqrt(q*q-h*h); p[j].r=x+sqrt(q*q-h*h); j++; } } sort(p,p+j,cmp); double R=0,mark=0; int len=0; i=0; while(i<j&&mark<w) { bool jud=0; while(p[i].l<=mark&&i<j) { jud=1; R=max(R,p[i].r); i++; } if(jud) { mark=R; R=0; len++; } else break; } if(mark>=w) printf("%d\n",len); else puts("0"); } return 0; }