平衡石头

Evg*_*niy 5 c++ algorithm dynamic-programming

你有许多已知重量为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;
}
Run Code Online (Sandbox Code Playgroud)

但它有点幼稚.它需要太多内存,我需要一些提示来简化它.有更有效的方法吗?

kra*_*ich 2

您可以通过进行以下观察来减少内存使用量:

  1. 您的代码在任何时候最多只使用ptrarray数组的两层。

  2. 如果在每一层中从最大索引到最小索引进行迭代,则可以重写前一层。这样你就只需要一个数组。

这是经过此优化的伪代码:

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
Run Code Online (Sandbox Code Playgroud)

它需要O(max_capacity)内存(而不是O(max_capacity * number_of_items))。

更多优化:您可以使用布尔数组(指示总和是否i可达)并选择最后最大的可达总和,而不是存储小于或等于的最大总和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
Run Code Online (Sandbox Code Playgroud)

这样代码变得更简单、更高效(时间复杂度在技术上是相同的,但在实践中要快得多)。

这里有一个警告:您需要在编译时知道 的大小std::bitset,因此如果不可能,您将需要不同的位集实现。