剪绳子(AcWing 680)
作者:互联网
剪绳子
https://www.acwing.com/problem/content/submission/code_detail/3421444/
描述
有N根绳子,第i根绳子长度为LiLi,现在需要M根等长的绳子,你可以对N根绳子进行任意裁剪(不能拼接),请你帮忙计算出这M根绳子最长的长度是多少。
输入格式
第一行包含2个正整数N、M,表示原始绳子的数量和需求绳子的数量。
第二行包含N个整数,其中第 i 个整数LiLi表示第 i 根绳子的长度。
输出格式
输出一个数字,表示裁剪后最长的长度,保留两位小数。
数据范围
1≤N,M≤1000001≤N,M≤100000,
0<Li<1090<Li<109
输入样例:
3 4
3 5 4
输出样例:
2.50
样例解释
第一根和第三根分别裁剪出一根2.50长度的绳子,第二根剪成2根2.50长度的绳子,刚好4根。
解答
大致思路
- 每次截取长度为d的绳子, n根绳子总共可以截取k条该绳段
- 如果 k > m, 可能恰好,也可能截取的长度过短
- 如果 k < m, 说明截取的长度过长, 需要减小d
- 解题的关键就是: 如何判断当 k > m时,是恰好还是截取的长度过短?
思路一(从小累加或者从大累减):
- 从d=0.01(最小单位开始)
- 如果k > m, 就延长一点截取长度 d = d+ 0.01
- 如果 k < m, 说明截取的长度太长了,那么 d - 0.01就是最佳结果
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int m = scanner.nextInt();
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
int x = scanner.nextInt();
arr[i] = x;
}
Arrays.sort(arr);
double d = 0;
int k = Integer.MAX_VALUE; //可以分为k条长度为d的绳子
while (k >= m) {
d += 0.01;
k = 0;
for (int i = 0; i < n; i++) {
k += (int)arr[i]/d;
}
}
System.out.println(String.format("%.2f", d-0.01));
}
}
思路二(从两边向中间趋近,即二分法)
- 从l=0.01, r = 最长绳子的长度
- 截取长度取中间值mid = (l + r)/2;
- 如果k < m, 说明太长 r = mid
- 如果k > m, l = mid
- 直到 l==r,说明截取的长度刚刚好。(差值小于0.01就算相等)
为了能够进一步减少迭代的次数
- l = 最长一个绳子 / m, r = sum/m
标签:arr,0.01,int,截取,绳子,长度,680,AcWing 来源: https://www.cnblogs.com/loserwang/p/14290046.html