你有许多已知重量为w1,...,wn的宝石。编写一个程序,将石头重新排列成两堆,使两桩之间的重量差异最小。 我有dp算法:
int max(int a, int b){
return a >= b ? a : b;
}
int diff(int* weights, int number_elements, int capacity){
int **ptrarray = new int* [capacity + 1];
for (int count = 0; count <= capacity; count++) {
ptrarray[count] = new int [number_elements + 1];
}
for (int i = 0; i <= number_elements; ++i){
ptrarray[0][i] = 0;
}
for (int i = 0; i <= capacity; ++i){
ptrarray[i][0] = 0;
}
for (int i = 1; i <= number_elements; ++i){
for (int j = 1; j <= capacity; ++j){
if(weights[i - 1] <= j){
ptrarray[j][i] = max(ptrarray[j][i - 1], ptrarray[j - weights[i - 1]][i-1] + weights[i - 1]);
} else{
ptrarray[j][i] = ptrarray[j][i - 1];
}
}
}
return ptrarray[capacity][number_elements];
}
int main(){
int capacity;
int number_elements;
cin >> number_elements;
int* weights = new int[number_elements];
int sum = 0;
int first_half;
for (int i = 0; i < number_elements; ++i){
cin >> weights[i];
sum+=weights[i];
}
first_half = sum / 2;
int after;
after = diff(weights, number_elements, first_half);
cout << sum - 2*after;
return 0;
}
但它有点幼稚。它需要太多内存,我需要一些提示来简化它。有更有效的方法吗?
答案 0 :(得分:2)
您可以通过进行以下观察来减少内存使用量:
您的代码随时只能使用ptrarray
数组的最多两层。
如果从每个图层中的最大索引到最小索引进行迭代,则可以重写上一个图层。这样你只需要一个数组。
以下是具有此优化的伪代码:
max_weight = new int[max_capacity + 1](false)
max_weight[0] = true
for weight in weights:
for capacity in [max_capacity ... weight]:
max_weight[capacity] = max(max_weight[capacity], max_weight[capacity - weight] + weight
它需要O(max_capacity)
内存(而不是O(max_capacity * number_of_items)
)。
还有一些优化:你可以使用一个布尔数组(来指示和i
是否可达)并在最后选择最大的可达总和,而不是存储小于或等于{的最大和。 {1}}。此外,您可以使用i
而不是布尔数组来获得std::bitset
时间复杂度(其中O(max_capacity * num_items / world_len)
是机器可以执行逻辑运算的最大整数类型的大小) 。添加一个权重看起来像world_len
。
所以最终版本看起来像这样:
reachable |= (reachable << weight)
这种方式变得更加简单和高效(时间复杂度在技术上是相同的,但在实践中要快得多)。
这里有一点需要注意:你需要在编译时知道reachable = bitset(max_capacity + 1)
reachable[0] = true
for weight in weights:
reachable |= reachable << weight
return highest set bit of reachable
的大小,所以如果不可能,你需要一个不同的bitset实现。