题目描述
我们有n根的木棍。现在从这些木棍中切割出来m条长度相同的木棍,问这m根木棍最长有多长?
输入数据
- 第一行输入两个数字,n和m n(1<=n<=1000)为木棍数目 m(1<=m<=1000)为需要切割出的相同长度的木棍数目
- 随后n个正整数,表示原始木棍的长度(<=10000)
输出数据
每组输出一行结果,表示切割后绳子的最长长度(保留两位小数)
样例输入
4 5
5 6 7 8
样例输出
4.00
初始思路
- 因为要求切割的最大长度,本来想着从木棍长度中找到最大的长度,不断递减向下寻找,直到能切割的数目>= m。!不过不可以,因为切割的长度极有可能不为整数。
正解思路
- 明确切割木棍的长度最粗略的范围就是0到当前木棍中最长的那个
- 明确范围之后,我们就可以使用二分查找了(因为数据是有序的)
- 每一次查找要计算 以当前mid指向的长度 切割的 木棍数目num
- 若num 大于等于m(想要的数目) 说明木棍长度小了 所以要更新left为mid
- 反之 更新 right 为mid
- 直到left 等于right时,就找到了满足当前条件的最长的切割长度了
代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cmath> //round四舍五入
using namespace std;
int main()
{
int n, m;
vector<int> lens;
cin >> n >> m;
for (int i = 0; i < n; i++)
{
int temp;
cin >> temp;
lens.push_back(temp);
}
auto max = max_element(lens.begin(), lens.end()); //max_element 返回的是迭代器
double l = 0, r = *max; //能切割的木棒长度 最粗略的范围就是0到当前木棒中最大的
double mid;
while (l + 0.01 < r) //不断更新范围 直到 l = r = 最佳解
{
int num = 0;
mid = round(((l + r) / 2.00) * 100) / 100.00; //保证精度
// float middd = round(l + r) / 2.00; //不可以 (4+4.5)=4.5
for (int i = 0; i < n; i++)
num += (int)(lens[i] / mid); //针对当前长度 看每个lens能切割成多少个
if (num >= m) //当前的切割 得到的木棍多 说明当前的切割长度小了
l = mid;
else
r = mid;
}
printf("%.2f", l);
system("pause");
return 0;
}
补充
- mid = round(((l + r) / 2.00) * 100) / 100.00; 为了保证精度到小数点后两位
- num += (int)(lens[i] / mid); 因为木棍切割只能向下取整,所以int的除法刚好合适
- max_element() 返回容器中最大值的迭代器,所以输出值的话要对其取 *
- 对于格式化的输入和输出,scanf 和 printf更方便
- 若文章存在问题,还请各位大佬批评指正,共同进步。