You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

88 lines
2.7 KiB

2 years ago
package class45;
import java.util.Arrays;
// 来自京东笔试
// 小明手中有n块积木并且小明知道每块积木的重量。现在小明希望将这些积木堆起来
// 要求是任意一块积木如果想堆在另一块积木上面,那么要求:
// 1) 上面的积木重量不能小于下面的积木重量
// 2) 上面积木的重量减去下面积木的重量不能超过x
// 3) 每堆中最下面的积木没有重量要求
// 现在小明有一个机会除了这n块积木还可以获得k块任意重量的积木。
// 小明希望将积木堆在一起,同时希望积木堆的数量越少越好,你能帮他找到最好的方案么?
// 输入描述:
// 第一行三个整数n,k,x1<=n<=2000000<=x,k<=1000000000
// 第二行n个整数表示积木的重量任意整数范围都在[1,1000000000]
// 样例输出:
// 13 1 38
// 20 20 80 70 70 70 420 5 1 5 1 60 90
// 1 1 5 5 20 20 60 70 70 70 80 90 420 -> 只有1块魔法积木x = 38
// 输出2
// 解释:
// 两堆分别是
// 1 1 5 5 20 20 (50) 60 70 70 70 80 90
// 420
// 其中x是一个任意重量的积木夹在20和60之间可以让积木继续往上搭
public class Code01_SplitBuildingBlock {
// 这是启发解
// arr是从小到大排序的x是限制固定参数
// 当前来到i位置积木重量arr[i]
// 潜台词 : 当前i位置的积木在一个堆里堆的开头在哪之前已经决定了
// i i+1 该在一起 or 该用魔法积木弥合 or 该分家
// 返回值arr[i....]最少能分几个堆?
public static int zuo(int[] arr, int x, int i, int r) {
if (i == arr.length - 1) {
return 1;
}
// i没到最后一个数
if (arr[i + 1] - arr[i] <= x) { // 一定贴在一起
return zuo(arr, x, i + 1, r);
} else { // 弥合!分家
// 分家
int p1 = 1 + zuo(arr, x, i + 1, r);
// 弥合
int p2 = Integer.MAX_VALUE;
int need = (arr[i + 1] - arr[i] - 1) / x;
if (r >= need) {
p2 = zuo(arr, x, i + 1, r - need);
}
return Math.min(p1, p2);
}
}
// 这是最优解
// arr里装着所有积木的重量
// k是魔法积木的数量每一块魔法积木都能变成任何重量
// x差值后 - 前 <= x
public static int minSplit(int[] arr, int k, int x) {
Arrays.sort(arr);
int n = arr.length;
int[] needs = new int[n];
int size = 0;
int splits = 1;
for (int i = 1; i < n; i++) {
if (arr[i] - arr[i - 1] > x) {
needs[size++] = arr[i] - arr[i - 1];
splits++;
}
}
if (splits == 1 || x == 0 || k == 0) {
return splits;
}
// 试图去利用魔法积木,弥合堆!
Arrays.sort(needs, 0, size);
for (int i = 0; i < size; i++) {
int need = (needs[i] - 1) / x;
if (k >= need) {
splits--;
k -= need;
} else {
break;
}
}
return splits;
}
}