ACM ICPC - 4212 - Candy

# Problem Info

Type: Regional
Continent: South America
Year: 2008

# Problem Statement

In this contest a random number of boxes containing candies are disposed in M rows with N columns each (so, there are a total of \$M x N\$ boxes). Each box has a number indicating how many candies it contains.
The contestant can pick a box (any one) and get all the candies it contains. But there is a catch (there is always a catch): when choosing a box, all the boxes from the rows immediately above and immediately below are emptied, as well as the box to the left and the box to the right of the chosen box. The contestant continues to pick a box until there are no candies left.
Can you maximize the number of candies he can pick?

# Explanation

There's a presentation I've written to teach how to solve the problem. It is in Spanish, I don't have enough time now to write the explanation here but I will as soon as I can.

The presentation: 4212-Candy.pdf

# Code

The C++ code that solves the problem using Top-Down approach with memoization is the following(4212-memo.cpp):

```#include <iostream>
#include <algorithm>
#include <stdint.h>
#include <map>

using namespace std;

uint32_t row;
uint32_t max_rows;

uint64_t f(uint32_t* array, uint32_t index, uint32_t size, map<uint32_t, uint64_t>& memo) {
if (index == size - 1)
return array[index];
if (index == size - 2)
return max(array[index], array[index + 1]);
if (memo.find(index) != memo.end())
return memo[index];
uint64_t tmp = array[index] + f(array, index + 2, size, memo);
tmp = max(tmp, f(array, index + 1, size, memo));
memo[index] = tmp;
return tmp;
}

int main() {

uint32_t n, m;
cin >> m >> n;
map<uint32_t, uint64_t> memo;
while (m > 0) {
for (uint32_t i(0); i < m; ++i) {
for (uint32_t j(0); j < n; ++j) {
cin >> row[j];
}
memo.clear();
max_rows[i] = f(row, 0, n, memo);
}
memo.clear();
cout << f(max_rows, 0, m, memo) << '\n';
cin >> m >> n;
}
}
```

The C++ code for the Bottom-Up approach is the following(4212.cpp):

```#include <iostream>
#include <algorithm>
#include <stdint.h>

using namespace std;

uint32_t row;
uint32_t max_rows;

uint32_t dp(uint32_t* r, uint32_t size) {
if (size > 1) {
r = max(r, r);
}
for (uint32_t i(2); i < size; ++i) {
r[i] = max(r[i-1], r[i] + r[i-2]);
}
return r[size-1];
}

int main() {

uint32_t n, m;
cin >> m >> n;
while (m > 0) {
for (uint32_t i(0); i < m; ++i) {
for (uint32_t j(0); j < n; ++j) {
cin >> row[j];
}
max_rows[i] = dp(row, n);
}
cout << dp(max_rows, m) << '\n';
cin >> m >> n;
}
}
```