题目链接 POJ 1064 Cable master
题目大意:
给你n根长度分别为 Li 的绳子。要从它们中切割出k条长度相同的绳子,问这k根绳子能切割的最大长度是多少。答案保留两位小数。
Input
第一行 n, k
接下来n行,每行一个2位小数的浮点数,表示 Li
Output
最大能切割的长度
Sample Input
4 11
8.02
7.43
4.57
5.39
Sample Output
2.00
题解:
二分范围为0到n条绳子中的最大长度。设cut(mid) 为每次二分计算出的剪得长度相同的绳子的条数, 我们要找的是 cut(mid) >= k 的最大的mid
在二分搜索时,要设置合理的结束条件来满足精度要求。1次循环可以把区间范围缩小一半, 100次循环就可以达到 10−30 的精度范围,基本上是没问题了。除此之外,也可以把终止条件设为 (r−l)>EPS ,指定一个区间大小。在这种情况下,如果EPS取得太小了,就有可能会因为浮点小数精度的原因导致陷入死循环,要小心。自以为对二分法比较熟练,但没想到WA了这么多次。。
由于是对浮点数二分,和整数的处理还是略有不同的
直接用printf(“%.2lf”, r) ,会自动帮你四舍五入。死舍没问题,五入就错了。
所以输出的时候特殊处理了一下。
代码:
#include <iostream>
#include <cstdio>
#define MAXN 10010
using namespace std;
int n, k;
double a[MAXN], M = 0.0;
int cut(double m) {
int cnt = 0;
for (int i = 0; i < n; i++) {
cnt += (int)(a[i]/m);
}
return cnt;
}
//二分
void solve() {
double l = 0.0, r = M;
for (int i = 0; i < 200; i++) {
double mid = 1.0*(l+r)/2;
if (cut(mid) >= k) l = mid;
else r = mid;
}
r *= 100;
int t = (int)r;
// t/100为整数部分, t%100为小数部分,长度不足2要补0
printf("%d.%02d\n", t/100, t%100);
}
int main() {
scanf("%d%d", &n, &k);
for (int i = 0; i < n; i++) {
scanf("%lf", &a[i]);
M = max(M, a[i]);
}
solve();
return 0;
}