题目来源: poj 1064 Cable master
题目概述:有N条绳子,他们的长度分别为Li,如果从它们中切割出k条长度相同的绳子的话,这K条绳子每条能有多长?
思路:使用二分法,判断最大值的范围,有三种情况:
- 当前剪的总数 小于 题目要求的K条,这时候我们确定,当前的区间范围来说,右边界过大,导致中间值middle过大,所以要将右边界=middle_value。
- 当前剪的总数相等题目要求的k条,这时候我们确定,当前的区间范围来说,middle正处于合适的范围区间,但是middle的取值是不是最大值呢,需要middle的数值扩大,所以将左边界扩大,左边界 = middle_value.
- 当前剪得的总数大于题目要求的k条,这时候我们确定,当前区间范围来说,middle的取值满足要求,但是是否是最大值,还是需要重新确认边界,所以左边界=middle,在此扩大middle的取值
注意:因为此时左边界(left_value),右边界(right_value),中间值(middle_value)都是浮点数,所以判断区间的时候会有两种方法:
- 左边界 - 右边界 > 一个足够小的数值,一般都设置为1e-5
- 一种是循环到合适的数值,一般来说,循环一百次,相当于达到了10的-30次方的精度,也是足够的
#include<iostream>
#include<stdio.h>
#include<math.h>
#define INF 9999999;
using namespace std;
bool pd_section (double middle, double* dataSet, int K, int N){
int num = 0;
for (int i=0; i<N; i++){
num += (int)(dataSet[i] / middle);
}
bool result = num >= K ? true : false;
return result;
}
int main () {
int N,K;
double dataSet[10001];
while (cin>>N>>K){
for (int i=0; i<N; i++){
cin>>dataSet[i];
}
double start_flag, end_flag;
start_flag = 0;
end_flag = INF;
for (int i=0; i<=100; i++){
double middle_flag = (start_flag + end_flag) / 2;
if ( pd_section(middle_flag, dataSet, K, N)){
start_flag = middle_flag;
} else {
end_flag = middle_flag;
}
}
printf("%.2lf\n", floor(end_flag * 100) / 100);
}
return 0;
}