因此,更正式地说,我得到了N个数字,需要将它们分成K组,而这些组中没有这些组是空的。每组中的范围总和需要最小化。例如:
N = 4,K = 2,输入为{5,3,1,1}。
一种可能的解决方案是{5,3},{1,1}。范围之和为2((5-3)+(1-1))。
另一种看待它的方法是{1,1,3} {5},它也是2((3-1)+(单个数字的范围是0))。
范围始终是组中最大数字与组中最小数字之间的差异。
当我搜索互联网时,很明显我需要使用动态编程,但我提出的所有内容都是K = 2的解决方案。
有人可以帮忙吗?
答案 0 :(得分:2)
答案 1 :(得分:0)
通过动态编程,你想出了一个k = 2的解决方案。现在想想如何将它扩展到k = 3.
假设f2(n)返回k = 2和前n个数的最优解,f3(n)= f2(n-m)+ err(n-m,n)。这是扩展它的一种方式。
答案 2 :(得分:0)
假设您的数据已经排序,您可以在线性时间内完成。
您可以在min_value
和max_value
之间的轴上查看数据。简而言之,聪明的解决方案不使用非连续组,因此任何聪明的解决方案都可以表示为轴上的一组K
段,每个段[x1, x2]
代表数据中x1
之间的所有数字。 1}}和x2
。
您的解决方案的总费用是所有段长度的总和,也是max_value - min_value - (space between all your segments)
。段之间的空间本身由K - 1
"空段"组成,即没有输入数字,即两个连续输入数字之间的段。你想要的是最大化K - 1
这些段的长度之和。
所以你要做的就是(简单版):
如果您的不同值的数量大于K,则必然所有组都将为非空。如果不是,您可以轻松拆分包含相同值的重复项的组,以使所有组都为非空。
复杂性(如果已经排序):O(n * k)(最多)如果K是常数则是O(n)。如果没有,只需改进搜索最佳K-1段以获得最多O(n log(n))
如上所述,额外的存储器复杂性很容易为O(K)
答案 3 :(得分:0)
因此,在这个问题中,我们希望最小化组的范围。
所以我们假设我们有数组A = {1,3,5,7,5,2}
每个数组的最大范围为max[a]-min[a]
,最小范围0
我们可以使用二进制搜索的变体来找到最小范围,这个答案是关于组必须包含字母数字的约束。
对于二进制搜索,我们需要选择由数组的最小和最大范围给出的边界。
这个psuedo / java代码看起来像这样。
main(){
int upper = max(A)-min(A);
int lower = 0;
while (true) {
int mid = upper-lower;
int blocks = calculateBlockCount(A, mid);
if (blocks < K) {
upper = mid - 1;
}
else if (blocks > K) {
lower = mid + 1;
}
else {
return upper;
break;
}
}
}
private static int calculateBlockCount(int[] array, int range) {
int count = 0;
int[] dumie_array;
int dumie_array[].add[array[0]];
for (int i = 0; i < array.length; i++) {
int dumie_array[].add[array[i]]
if (Func_range(dumie_array) > range) {
count++;
dumie_array = array[i];
}
else {
dumie_array.add(array[i]);
}
}
return count;
}
private static int Func_range(int[] input) {
int range = 0;
range= max(input)-min(input)
return sum;
}
希望stil帮助
我认为大部分都适用于java,只有C ++所具有的添加功能才存在。 (不想通过制作一个arraylist来写这么多。)但我认为该计划的想法应该是明确的。
这都是基于这篇文章
Need explanation for algorithm searching minimal large sum。
这是一个非常相似的问题。
干杯, 的Gijs