nyoj 12 喷水装置(二)
题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=12
这道题自己没写网上找的代码,不过思路很清晰的主要思想就是先转化成直线上的线段覆盖问题,就是求用最少的线段数把整个区域都覆盖了,最终求的是所用的线段数,不能覆盖的输出0;
题目给出了点的坐标和半径,只用带入即可求出线段的左右边界,这题需要注意的一点就是利用贪心思想选取线段的时候,按左坐标由小到大排序,
对于下面几种情况的处理
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<stdio.h> 2 #include<string.h> 3 #include<math.h> 4 #include<algorithm> 5 using namespace std; 6 struct ps 7 { 8 double left;//**左交点**// 9 double right;//**右交点**// 10 }w[10001]; 11 bool comp(ps a,ps b)//**还是按照左交点的大小进行排序**// 12 { 13 if(a.left<b.left) return true; 14 return false; 15 } 16 int main() 17 { 18 int ncases,n,i,width,high,x,r,count,flag; 19 double len,sum,max; 20 scanf("%d",&ncases); 21 while(ncases--) 22 { 23 flag=1;sum=0;count=0; 24 scanf("%d %d %d",&n,&width,&high); 25 for(i=0;i<=n-1;i++) 26 { 27 scanf("%d %d",&x,&r); 28 len=(double)r*r-(double)high/2*high/2; 29 if(len>=0) {len=sqrt(len);}//**以前把这布直接并入到sqrt(len),结果忘了len可以小于0,一直WA**// 30 if(len<0) {len=0;}//**覆盖不到,这个长度就可以忽略掉**// 31 w[i].left=x-len; 32 w[i].right=x+len; 33 } 34 sort(w,w+n,comp); 35 while(sum<width)//**关键思想**// 36 { 37 max=0;//**代表比前一个装置能够辐射的范围往右延长的最大值**// 38 for(i=0;i<=n-1&&w[i].left<=sum;i++)//**w[i].left<=sum保证两个碰水装置可以相交,也就是说两点直接的能够完全覆盖**// 39 { 40 if((w[i].right-sum)>max)//**找出既能保证完全覆盖又能保证这点能够达到的右交点最大,即需要的喷水装置最少**// 41 { 42 max=w[i].right-sum;//**找出最大值**// 43 } 44 } 45 if(max==0)//**说明w[i].left>sum,表示其中一个点的右交点跟另外一个点的左交点没有连接上,即不能完全覆盖**// 46 { 47 flag=0; 48 break; 49 } 50 else 51 { 52 sum=sum+max;//**更新能够覆盖的宽度**// 53 count++; 54 } 55 } 56 if(flag==1) 57 { 58 printf("%d\n",count); 59 } 60 else 61 { 62 printf("0\n"); 63 } 64 } 65 return 0; 66 }