喷水装置(二)
-
描述
-
有一块草坪,横向长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(线段A),求怎么用最少的小线段(L1,L2,L3,,,,,,Ln)才能全部覆盖线段A的问题
本题出的很好,考验人的发散思维,,,,,come on!!!!!!!!#include<stdio.h>
#include<algorithm>
#include<math.h>
using namespace std;
const int MAX=10001;
struct p{
double left,right;
}a[MAX];
bool cmp(struct p a,struct p b){
return a.left<b.left;
}
int main()
{
int i,j,num,len,wight,times,count,biaoji;
double wight_2;
scanf("%d",×);
while(times--)
{
biaoji=1;
count=0;
scanf("%d%d%d",&num,&len,&wight);
wight_2=wight/2.000000;
for(i=0;i<num;i++)
{
int x,r;
double temp_w;
scanf("%d%d",&x,&r);
temp_w=sqrt(r*r-wight_2*wight_2);
if(temp_w>0) // 排除r<=wight_2情况
{ //(a[0].right减去a[0].left)形成线段L0,最终 形成小线段(L1,L2,L3,,,,,,Ln)
a[i].left=x-temp_w;
a[i].right=x+temp_w;
}
}
sort(a,a+num,cmp); //按照小线段L的左端点从小到大排序
double Max=0,sum=0; //在使用本装置之前已经被覆盖的长度0
while(sum<len)
{
Max=0;
for(i=0;i<num&&a[i].left<=sum;i++) //本for循环每次找出a[i].left<=sum和 覆盖长度a[i].right-sum最长的一个;
{
if(a[i].right-sum>Max)Max=a[i].right-sum;
}
if(Max==0){biaoji=0; break; }//若有一次为0,表示找不到这条覆盖的线,也就是永远填满不了这条线
else{ count++; sum+=Max; }
}
if(biaoji) printf("%d\n",count);
else printf("0\n");
}
return 0;
}
第二种解法:额,,,是别人的代码,,,不懂,,,坐等大神回复啊
#include<stdio.h>
#include<math.h>
#include<algorithm>
using namespace std;
struct p
{
double x;
double r;
}a[10004];
int cmp(p a,p b){return a.r<b.r;}//按照半径进行升序排列,排列后进行运算a[i].x=f-sqrt(g*g-h*h/4.0);a[i].r=sqrt(g*g-h*h/4.0)+f;的 //顺序就完全乱了,后面的还怎么做??????
int main()
{
int t,n,w,h,i,j,x,r;
int f,g,l;
double max,sum;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&n,&w,&h);
for(i=0,j=0;i<n;i++)
{
scanf("%d%d",&x,&r);
if(r>h/2.0)//排除r<=h/2.0无用情况
{
a[j++].x=x;
a[j-1].r=r;
}
}
if(w<=h&&j==0){printf("0\n");continue;}
if(w<=h&&j>0){printf("1\n");continue;}
sort(a,a+j,cmp);//按照半径从小到大排序
for(i=0;i<j;i++)
{
f=a[i].x;
g=a[i].r;
a[i].x=f-sqrt(g*g-h*h/4.0);//(a[0].right-a[0].left)形成线段L0,
a[i].r=sqrt(g*g-h*h/4.0)+f; //a[i].x为L0的左端点坐标 , a[i].r为L0的左端点坐标
}
l=0;max=0;sum=0;
while(sum<w)
{
for(i=0;i<j;i++)
{
if(a[i].x<=sum&&(a[i].r-sum>max))
max=a[i].r-sum;
}
if(max==0)//注意这个地方,没有这个判断的话会超时
{
l=0;
break;
}
sum+=max;
l++;
max=0;
}
printf("%d\n",l);
}
return 0;
}
-
第一行输入一个正整数N表示共有n次测试数据。