题意:
给出n条线段,以米的单位给出,小数点后两位(精确到厘米),要对这些线段裁剪,裁剪出m条等长的线段,返回最长的线长。
输入:
输入文件的第一行包含两个整数 N 和 K,用空格分隔。N (1 = N = 10000) 是库存中的电缆数量,K (1 = K = 10000) 是请求的件数。第一行后面是 N 行,每行一个数字,指定库存中每根电缆的长度(以米为单位)。所有电缆的长度至少为 1 米,最长为 100 公里。输入文件中的所有长度都以厘米精度写入,小数点后正好有两位数字。
输出:
将 Cable Master 可以从库存中的电缆切割以获得所需件数的最大长度(以米为单位)写入输出文件。该数字必须以厘米精度书写,小数点后恰好有两位数字。
如果无法切割要求的每件至少一厘米长的件,则输出文件必须包含单个数字“0.00”(不带引号)。
如果无法切割要求的每件至少一厘米长的件,则输出文件必须包含单个数字“0.00”(不带引号)。
学习笔记:
本题思路不难,就是二分法,但是本题有很多细节要注意:
1.最长的电缆是100公里,不是100米,可别看错了
2.不足一厘米的部分要去掉,也就是说,不是四舍五入,必须向下取整。这个可以用floor函数实现,它会对一个浮点数向下取整。
3.小数进行二分是没有尽头的,所以要设置终止条件,一般有两种办法:第一种是设定循环次数,一般循环100次是足够的,第二种是设定最大差值eps,当左右边界的差值小于eps的时候说明精度足够了,我个人偏向第二种做法。但是要特别注意的是,eps不能设置的太小,不然如果小于double的精度的话会导致死循环问题。一般eps设为1e-7即可。
4.cin貌似不能用来输入浮点数?(我不太确定,但是我把scanf换成cin就TLE了,不知道是有什么问题)
代码:
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <string.h>
#include <climits>
typedef long long ll;
using namespace std;
const int MAXN = 1e4+5;
const double eps = 1e-7;
int n; // 绳子数量
int k; //要求分成的段数
double L[MAXN]; // 记录所有绳子长度的数组
int isEnough(double x){
int sum = 0;
for(int i=0; i<n; i++){
sum += (int)(L[i] / x);
}
return sum >= k;
}
int main(){
scanf("%d%d", &n, &k);
for(int i=0; i<n; i++){
scanf("%lf", &L[i]);
}
double lb = 0.0, ub = 1e5+5;
while(ub - lb > eps){
double mid = (lb + ub) / 2;
if(isEnough(mid)) lb = mid;
else ub = mid;
}
printf("%.2f\n", floor(ub*100)/100);
}