1

I'm trying to learn dynamic programming and hence I'm trying to solve UVA 11450. Since I know I could solve this question using backtracking, I decided to solve it using backtracking and then add memoization to the code. However, I'm unable to do this.

Here is the commented code without memoization:

#include <bits/stdc++.h>

using namespace std;


bool b;                         // this tells us if a solution is found or not
int c;                          // store input c
vector <vector <int>> arr;     // declare a global array to store the type and cost of the garments


int money = INT_MAX;           // these two fields store the most optimal solution found so far
vector <int> garr;


// this function fills 'c' - the candidates for the k'th postition
void construct_candidates(vector <int> &a, int k, int m, vector<int> &c)        
{
    for (int i: arr[k])
    {
        if (i <= m ) c.push_back(i);    // if cost of the model 'i' of garment 'k' is less than or equal to money remaining,
    }                                   // put it in array 'c'.
}


void backtrack(vector <int> &a, int k, int m)
{
    vector <int> c;                     // this array stores the candidates for postion k.

    if (k == a.size() - 1)              // if (is_a_soln) process_solution
    {
        if (m < money)
        {
            b = true;
            money = m;
            garr = a;
        }
    }
    else                                // else backtrack with updated parameters
    {
        k++;
        construct_candidates(a, k , m, c);
        for (int i = 0; i < c.size(); i++)
        {
            a[k] = c[i];
            backtrack(a, k, m - c[i]);
        }
    }
}


int main()
{

    int n;
    cin >> n;
    while (n--)
    {   
        b = false;                              // initialising global variables
        money = INT_MAX;
        arr.clear();
        int m;
        cin >> m >> c;
        arr = vector <vector <int>>(c);

        for(int i = 0; i < c; i++)              // storing the input in arr
        {
            int k;
            cin >> k;
            arr[i] = vector <int> (k);
            for (int j = 0; j < k; j++)
            {
                cin >> arr[i][j];
            }
        }

        vector <int> a(c, -1);         // the backtracking code will attempt 
                                       //to fill this array with optimal garments

        backtrack(a, -1, m);                      

        if (b) cout <<m - money << endl;
        else cout << "no solution" << endl;
    }

    return 0;
}

Now, to add memoization, I tried doing:

vector <vector <int>> dp(20, vector<int> (201, -1));
void backtrack(vector <int> &a, int k, int m)
{
    if (dp[k][m] != -1)                    // this is
    {                                      // the 
        k++;                               // part
        a[k] = dp[k][m];                   // that 
        backtrack(a, k, m - a[k]);         // is
    }                                      // added
    else
    {
        vector <int> c;                    

        if (k == a.size() - 1)              
        {
            if (m < money)
            {
                b = true;
                money = m;
                garr = a;
            }
        }
        else                                
        {
            k++;
            construct_candidates(a, k , m, c);
            for (int i = 0; i < c.size(); i++)
            {
                a[k] = c[i];
                backtrack(a, k, m - c[i]);
            }
        }
    }
}

But I don't know where or how to add the part that actually puts the optimal garment at position k in the DP table. Any help is much appreciated.

Evil_Transistor
  • 188
  • 1
  • 1
  • 10
  • First of all, why do you even need to store the optimal set of garments? The problem only asks for the maximum cost, so you only have to store that. In your case, you're using a global variable to keep track of the maximum cost that you've seen instead of returning it from the function, so all you need to keep track of in your DP table is whether you've already explored a state. If you reach a state that you've already explored, you can immediately return without doing anything since you know that any optimal states from here on have already been explored previously. – eesiraed Jun 12 '19 at 18:44
  • @AlexanderZhang Yeah that true. I did that just because I thought it'd be nice to know which choices lead to the optimal solution. – Evil_Transistor Jun 12 '19 at 21:00
  • @AlexanderZhang I initially thought that your comment was only saying that 'garr' was not required in the code. But on reading it again today, I realised it also tells how to go about writing the DP table. So, I implemented it and it works. Thanks for the help. – Evil_Transistor Jun 14 '19 at 17:11

1 Answers1

0

Thanks to the very helpful comment by @AlexanderZhang, I have solved the question. Refer to his comment for the details if interested. Here is the code:

vector <vector <int>> dp(20, vector<int> (201, -1));
void backtrack(vector <int> &a, int k, int m)
{
    k++;
    if (dp[k][m] != -1)
    {
        return;
    }
    else
    {
        dp[k][m]++;
        vector <int> c;                     // this array stores the candidates for postion k.

//        for (int kj : a) cout << kj << " ";
//        cout << endl;

        if (k == a.size() )              // if (is_a_soln) process_solution
        {
            if (m < money)
            {
                b = true;
                money = m;
                garr = a;
            }
        }
        else                                // else backtrack with updated parameters
        {
//            k++;
            construct_candidates(a, k , m, c);
            for (int i = 0; i < c.size(); i++)
            {
                a[k] = c[i];
                backtrack(a, k, m - c[i]);
            }
        }
    }
}
Evil_Transistor
  • 188
  • 1
  • 1
  • 10