Problem p03183 (C++)

Buggy submission (status: Runtime Error):
#include <bits/stdc++.h>
using namespace std;
#define ll long long int

struct Block {
  ll s, w, v;
  bool operator<(const Block &b1) {
    ll s1 = s, w1 = w, s2 = b1.s, w2 = b1.w;
    return s1 + w1 <= s2 + w2;
  }
};

ll tower(Block arr[], int n) {

  // Suppose if we have 3 blocks with (weight, solidness, value) as:
  // (1, 2, 1)
  // (1, 3, 1)
  // (1, 1, 1)

  // If we try to find the best subsequence having this order itself
  // then we will be able to get the maximum value as 2 only
  // Although the maximum value can be 3
  // by taking all the three in the order: 3, 1, 2
  // Hence to avoid checking of all the possible permutations,
  // we need to sort them in some order

  // Now we need to decide the comparator function for sorting
  // Suppose we have 2 blocks: 1 and 2
  // and they should be such that 1 should be above 2
  // Then a good (or strong) comparator function will ensure
  // that 1 comes before 2 in the array always
  // For 2 to be below 1, this condition must be satisfied: s2 >= w1
  // Also notice that for 1 to be below 2: s1 >= w2 but we don't want this
  // So we also want to satisfy: s1 < w2
  // So that both conditions are satisfied simultaneously:
  //              1) 2 is below 1
  //              2) 1 is never below 2
  // Both conditions must be satisfied to avoid any contradiction
  // Hence there are 2 conditions: s2 >= w1 and s1 < w2
  //                               s2 >= w1 and w2 > s1
  // On combining these 2 conditions: s2+w2 >= w1+s1 OR s1+w1 <= s2+w2
  // This single condition will ensure that 2 comes below 1 OR
  // 2 comes after 1 in the array AND also there is no contradiction

  // I have already defined the comparator in the structure definition itself
  sort(arr, arr + n);

  // Now we apply Dynamic Programming:
  // dp[i][j] stores the maximum sum of value of some subsequence
  // considered till i-th element and having the sum of weights as 'j'
  // So whenever a new element comes, we check for which maximum
  // value in dp[i-1][],
  // the solidness of that new element is greater than or equal to
  // the value in dp[i-1][] (sum of some weights) and then update
  // the dp value corresponding to the new sum of weights if better

  // The first dimension of dp[][] will be the no. of elements
  // Now we can take the second dimension to be the sum of all weights
  // but notice that the maximum allowed sum of weights
  // will be limited by the solidness of the bottom most block or
  // the last element which we pick from the array, i.e.
  // the maximum possible sum of weights for any subsequence will
  // be at max (maxS + maxW)
  // where maxS is the max sum of weights of all the blocks except the
  // bottom most block and maxW is the max weight of the bottom most block
  // Hence we can take the second dimension of size (maxS + maxW)

  int maxS = 0, maxW = 0;
  for (int i = 0; i < n; i++) {
    if (arr[i].s > maxS)
      maxS = arr[i].s;
    if (arr[i].w > maxW)
      maxW = arr[i].w;
  }

  vector<vector<ll>> dp(n + 1, vector<ll>(maxS + maxW + 1, 0));

  for (int i = 1; i <= n; i++) {
    int w = arr[i - 1].w, s = arr[i - 1].s, v = arr[i - 1].v;
    // We need to go to all the values of previous row
    // to also copy them to the current row
    for (int j = 0; j <= maxS + maxW; j++) {
      dp[i][j] = max(dp[i][j], dp[i - 1][j]);
      if (s >= j)
        dp[i][j + w] = max(dp[i - 1][j + w], dp[i - 1][j] + v);
    }
  }

  // The maximum value in dp[n][] is our answer
  ll maxSumOfValue = 0;
  for (int i = 0; i <= maxS + maxW; i++)
    if (dp[n][i] > maxSumOfValue)
      maxSumOfValue = dp[n][i];

  return maxSumOfValue;
}

ll towerOptimized(Block arr[], int n) {
  // Instead of maintaining a 2D array,
  // we can maintain a rolling 1D array like in knapsack
  sort(arr, arr + n);
  int maxS = 0, maxW = 0;
  for (int i = 0; i < n; i++) {
    if (arr[i].s > maxS)
      maxS = arr[i].s;
    if (arr[i].w > maxW)
      maxW = arr[i].w;
  }
  vector<ll> dp(maxS + maxW + 1, 0);
  for (int i = 1; i <= n; i++) {
    int w = arr[i - 1].w, s = arr[i - 1].s, v = arr[i - 1].v;
    for (int j = s; j >= 0; j--)
      dp[j + w] = max(dp[j + w], dp[j] + v);
  }
  ll maxSumOfValue = 0;
  for (int i = 0; i <= maxS + maxW; i++)
    if (dp[i] > maxSumOfValue)
      maxSumOfValue = dp[i];

  return maxSumOfValue;
}

int main() {
  int n;
  cin >> n;
  Block arr[n];
  for (int i = 0; i < n; i++)
    cin >> arr[i].w >> arr[i].s >> arr[i].v;
  // ll ans = tower(arr, n);
  ll ans = towerOptimized(arr, n);
  cout << ans;
  return 0;
}


Fixed submission:
#include <bits/stdc++.h>
using namespace std;
#define ll long long int

struct Block {
  ll s, w, v;
  bool operator<(const Block &b2) {
    ll s1 = s, w1 = w, s2 = b2.s, w2 = b2.w;
    return s1 + w1 < s2 + w2;
  }
};

ll tower(Block arr[], int n) {

  // Suppose if we have 3 blocks with (weight, solidness, value) as:
  // (1, 2, 1)
  // (1, 3, 1)
  // (1, 1, 1)

  // If we try to find the best subsequence having this order itself
  // then we will be able to get the maximum value as 2 only
  // Although the maximum value can be 3
  // by taking all the three in the order: 3, 1, 2
  // Hence to avoid checking of all the possible permutations,
  // we need to sort them in some order

  // Now we need to decide the comparator function for sorting
  // Suppose we have 2 blocks: 1 and 2
  // and they should be such that 1 should be above 2
  // Then a good (or strong) comparator function will ensure
  // that 1 comes before 2 in the array always
  // For 2 to be below 1, this condition must be satisfied: s2 >= w1
  // Also notice that for 1 to be below 2: s1 >= w2 but we don't want this
  // So we also want to satisfy: s1 < w2
  // So that both conditions are satisfied simultaneously:
  //              1) 2 is below 1
  //              2) 1 is never below 2
  // Both conditions must be satisfied to avoid any contradiction
  // Hence there are 2 conditions: s2 >= w1 and s1 < w2
  //                               s2 >= w1 and w2 > s1
  // On combining these 2 conditions: s2+w2 >= w1+s1 OR s1+w1 <= s2+w2
  // This single condition will ensure that 2 comes below 1 OR
  // 2 comes after 1 in the array AND also there is no contradiction

  // I have already defined the comparator in the structure definition itself
  sort(arr, arr + n);

  // Now we apply Dynamic Programming:
  // dp[i][j] stores the maximum sum of value of some subsequence
  // considered till i-th element and having the sum of weights as 'j'
  // So whenever a new element comes, we check for which maximum
  // value in dp[i-1][],
  // the solidness of that new element is greater than or equal to
  // the value in dp[i-1][] (sum of some weights) and then update
  // the dp value corresponding to the new sum of weights if better

  // The first dimension of dp[][] will be the no. of elements
  // Now we can take the second dimension to be the sum of all weights
  // but notice that the maximum allowed sum of weights
  // will be limited by the solidness of the bottom most block or
  // the last element which we pick from the array, i.e.
  // the maximum possible sum of weights for any subsequence will
  // be at max (maxS + maxW)
  // where maxS is the max sum of weights of all the blocks except the
  // bottom most block and maxW is the max weight of the bottom most block
  // Hence we can take the second dimension of size (maxS + maxW)

  int maxS = 0, maxW = 0;
  for (int i = 0; i < n; i++) {
    if (arr[i].s > maxS)
      maxS = arr[i].s;
    if (arr[i].w > maxW)
      maxW = arr[i].w;
  }

  vector<vector<ll>> dp(n + 1, vector<ll>(maxS + maxW + 1, 0));

  for (int i = 1; i <= n; i++) {
    int w = arr[i - 1].w, s = arr[i - 1].s, v = arr[i - 1].v;
    // We need to go to all the values of previous row
    // to also copy them to the current row
    for (int j = 0; j <= maxS + maxW; j++) {
      dp[i][j] = max(dp[i][j], dp[i - 1][j]);
      if (s >= j)
        dp[i][j + w] = max(dp[i - 1][j + w], dp[i - 1][j] + v);
    }
  }

  // The maximum value in dp[n][] is our answer
  ll maxSumOfValue = 0;
  for (int i = 0; i <= maxS + maxW; i++)
    if (dp[n][i] > maxSumOfValue)
      maxSumOfValue = dp[n][i];

  return maxSumOfValue;
}

ll towerOptimized(Block arr[], int n) {
  // Instead of maintaining a 2D array,
  // we can maintain a rolling 1D array like in knapsack
  sort(arr, arr + n);
  int maxS = 0, maxW = 0;
  for (int i = 0; i < n; i++) {
    if (arr[i].s > maxS)
      maxS = arr[i].s;
    if (arr[i].w > maxW)
      maxW = arr[i].w;
  }
  vector<ll> dp(maxS + maxW + 1, 0);
  for (int i = 1; i <= n; i++) {
    int w = arr[i - 1].w, s = arr[i - 1].s, v = arr[i - 1].v;
    for (int j = s; j >= 0; j--)
      dp[j + w] = max(dp[j + w], dp[j] + v);
  }
  ll maxSumOfValue = 0;
  for (int i = 0; i <= maxS + maxW; i++)
    if (dp[i] > maxSumOfValue)
      maxSumOfValue = dp[i];

  return maxSumOfValue;
}

int main() {
  int n;
  cin >> n;
  Block arr[n];
  for (int i = 0; i < n; i++)
    cin >> arr[i].w >> arr[i].s >> arr[i].v;
  // ll ans = tower(arr, n);
  ll ans = towerOptimized(arr, n);
  cout << ans;
  return 0;
}