这里才是入门0.0
现在有N(1 <= N <= 1000)条绳子,他们的长度分别为L1,L2,……,Ln(1 <= Li <= 10000),如果从他们中切割出K(1 <= K <= 1000)条长度相同的绳子,这K条绳子每条最长能多长?
Input
共有两行,第一行包含两个正整数N和K,用一个空格分割;第二行包含N个数,一次表示N条绳子的长度,两数间用一个空格分隔,每条绳子的长度的小数不超过两位。
Output
仅包含一个数,表示所得K条绳子的最大长度。答案四舍五入保留小数点后两位 原题的样例似乎出了个问题,样例的精确的答案是2.005,四舍五入的话应该是2.01才对。
Sample Input
4 11
8.02 7.43 4.57 5.39
Sample Output
2.01
题目好奇怪的感觉,简而言之就是N条绳子切割成K条等长度绳子问题。
若题目要求找到一个数满足一定条件且结果保留几位小数,则二分法+贪心算法。二分法不断逼近找这个数,贪心算法可以嵌在二分法里的判断条件来保证这个数满足一定的条件。
结合这道题目来说,二分法不断逼近找这个数,如果len太小了就在右半边找,如果len太大了,就在左半边找,直到len和真值(即要找的数)相差满足精度要求不影响结果输出即可。我们很难找到真值,所以题目一般都是保留几位小数,也就是满足相关精度即可。二分法的精髓也在于此,即不必找出真值,找的近似解即可。故可以用二分法做。
贪心算法主要体现在嵌在二分法里的Check()函数来保证这个数满足规定题目最长的条件。若Check()为真,说明当前len可以满足题目的K条的条件,但题目还要求得是最长的,所以len虽然满足了可以分为K条的条件,但说不定可以更长,所以返回真,继续在右半部分继续找,这体现了我要越长越好的贪心思想。
虽然有贪心算法这个术语,但其实我们很多时候在没有学算法的情况下也能写出贪心算法思想的代码。不要觉得算法有多么难,其实不看我说的贪心算法,只看个二分法即可。这道题核心算法就是二分法。贪心算法只不过仔细想想好像确实也体现了,所以说二分法+贪心更高大上更完善,但我不告诉你贪心,说不定你也可以写出贪心的思想。
总之,这类题记住二分法即可。
AC代码:
#include<iostream>
#include<iomanip>
using namespace std;
int n;
bool Check(double len,double a[],int target);
int main()
{
int m,i;
cin>>n>>m;
double a[n],mid,sum=0;
for(i=0; i<n; i++)
{
cin>>a[i];
sum=sum+a[i];
}
double l=0,r=sum;
while(r-l>1e-4)//保留两位小数,即结果逼近到小数点后第三位固定即可,故精度设为0.0001就可以了。
{//这个部分就是二分法
mid=l+(r-l)/2;
if(Check(mid,a,m))//mid还可以更得,在右半部分逼近
l=mid;
else//len太大了,应该小一点,在左半部分逼近
r=mid;
}
cout<<fixed<<setprecision(2)<<r<<endl;
return 0;
}
bool Check(double len,double a[],int target)//这个函数是二分法里的判断条件
{
int cnt=0;;
for(int i=0; i<n; i++)
{
cnt=cnt+(int)(a[i]/len);//整体加(int)
if(cnt>=target)//len还可以更得
return true;//返回在右半部分逼近
}
return false;//len太大了,应该小一点,故返回在左半部分逼近
}
永远相信美好🎈