ACM ICPC - 4212 - Candy

Problem Info

Type: Regional
Continent: South America
Year: 2008
Link: 4212 - Candy

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[100002];
uint32_t max_rows[100002];
 
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[100002];
uint32_t max_rows[100002];
 
uint32_t dp(uint32_t* r, uint32_t size) {
    if (size > 1) {
        r[1] = max(r[0], r[1]);
    }
    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;
    }
}
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License