问题描述:
有n条绳子,它们的长度为Li(Li<=1000),如果从它们中切割出k条长度相同的绳子的话,这k条绳子每条最长能有多长,答案保留到小数点后两位。
输入描述:
第一行输入两个整数n,k。表示有n条绳子和要切割出k条长度相同的绳子。
第二行输入n个数表示每条绳子的长度。
输出描述:
输出一个数,即k条绳子最长能有多长。保留到小数点后两位。
输入:
4 11
8.02 7.43 4.57 5.39
输出:
2.00
思路1:(暴力枚举)
枚举对象是绳子长度,从0.01到绳子的最大长度,步长为0.01(题目要求保留到小数点后两位)。对于枚举的每个长度,我们要验证在该长度下是否能切割出k条绳子,找出一个能切割且最长的长度,即满足Cnt(i)>=k的最大 i 。Cnt(i) 返回的是切割长度为 i 时可以切割绳子的条数。
for(double i=0.01;i<=Max;i+=0.01)
{
if(Cnt(i)>=k)
ans=i; //ans更新为更大的 i
else //Cnt(i) < k 说明长度已经过大了
break;
}
思路二:(二分枚举)
我们需要的是满足Cnt(i) >=k 的最大的 i。假设我们枚举的区间是 [L,R],存在Mid=(L+R)/2。
如果对于Cnt(Mid)>=k,说明Mid长度小了(或刚好合适),那么对于所有[L,Mid) 长度都小了,可以舍去[L,Mid),将L更新为Mid,新的枚举范围为[Mid,R]。
如果对于Cnt(Mid)<k,说明Mid长度大了,那么对于所有[Mid,R]长度都大了,可以舍去[Mid,R],将R更新为Mid-0.01。新的枚举范围更新为[L,Mid-0.01]。
最后的L即为k条绳子最大长度。
while(R-L>0.001)
{
double Mid=(L+R)/2;
if(Cnt(Mid)>=k)
L=Mid;
else
R=Mid-0.01;
}
二分枚举完整代码:
#include<stdio.h>
double Len[100];
int n,k;
int Cnt(double mid)
{
int cnt=0;
for(int i=0;i<n;i++)
cnt+=(int)(Len[i]/mid);
return cnt;
}
int main()
{
scanf("%d%d",&n,&k);
double Max=-1;
for(int i=0;i<n;i++)
{
scanf("%lf",&Len[i]);
Max=Max>Len[i]? Max:Len[i];
}
double L=0,R=Max;
while(R-L>0.001)
{
double Mid=(L+R)/2;
if(Cnt(Mid)>=k)
L=Mid;
else
R=Mid-0.01;
}
printf("%.2f\n",L);
return 0;
}