题目链接:https://cn.vjudge.net/contest/311860#problem/C
Sample Input
8 20 2
5 3
4 1
1 2
7 2
10 2
13 3
16 2
19 4
3 10 1
3 5
9 3
6 1
3 10 1
5 3
1 1
9 1
Sample Output
6
2
-1
解析:刚开始输入三个数,8 20 2。8个圆,矩形的长宽分别是20和2。
接下来8组数据:
每一组表示圆心离最左端的距离,和圆的半径。
问:把矩形完全覆盖,最少需要几个圆?
分析:需要解决:1.对数据如何处理,转化为熟悉的一个序列的问题。2.如何贪心?
图1
图二
所需的圆必须满足:1.直径大于矩形的宽度。2.圆覆盖的有效长度不是直径。(如图2,蓝色的没被覆盖),图1,红色部分是有效长度。覆盖的有效范围,转化为线段的长度。
贪心的问题:每一个线段的左端点,从小到大排序。贪心结束后,最最左边的端点必须保证小于或等于矩形的最左端。最最右边的端点必须保证大于或等于矩形的最右端。找到第一个左端点小于矩形左端点的线段,for循环,保证最右边尽可能大。for循环结束后,只找到一个。再进行for循环,找下一个。。。。。直至满足,找到一个线段的右端点大于或等于矩形的长度。
代码:
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stdlib.h>
#include<algorithm>
using namespace std;
int n,l,w;
int book[10005];
int k;//k为"有效圆"的个数
struct node{
double len;//圆心到左端点的长度
double limit1;//左范围
double limit2;//右范围
} s[10005];
int cmp(node x,node y){
return x.limit1<y.limit1;//左范围从小到大排序
}
int main(){
double len1,r1;
while(~scanf("%d%d%d",&n,&l,&w)){
k=0;//n个圆,草坪的长宽分别是l和w
for(int i=0; i<n; i++)//符合情况的存到结构体中
{
scanf("%lf %lf",&len1,&r1);
if(2*r1>w){
s[k].len=len1;
s[k].limit1=len1-sqrt(r1*r1-(w*w)/4.0);
s[k++].limit2=len1+sqrt(r1*r1-(w*w)/4.0);
}
}
sort(s,s+k,cmp);
if(s[0].limit1>0){
printf("-1\n");
continue;
}
int sum=0,flag,h;
double head=0,tail=0;
memset(book,0,sizeof(book));
while(1){
flag=0;
for(int i=0; i<k; i++){
if(s[i].limit1<=head&&s[i].limit2>=tail&&book[i]==0){
flag=1;
tail=s[i].limit2;//保证最右边尽可能的大
if(tail>=l)
flag=2;
h=i;
}
}
if(flag==1||flag==2){
book[h]=1;
sum++;
head=tail;
}
else
break;
if(flag==2)
break;
}
if(tail<l)
flag=0;
if(flag==0)
printf("-1\n");
else
printf("%d\n",sum);
}
return 0;
}
后记:也是降维处理的贪心:https://blog.csdn.net/lylzsx20172018/article/details/96123305