简体   繁体   中英

How to convert this recursive function to a dp based solution?

This is the recursive function

def integerPartition(m, n):
    if(n==0):
        return 0
    if(m ==0):
        return 1
    if(m<0):
        return 0

    return integerPartition(m,n-1) + integerPartition(m-n,n)

and this is what i have done in c++

        // n -> no. of persons
        // m -> amount of money to be distributed
        // dp table of order (n+1)*(m+1) 
        long long int dp[n+1][m+1] ;
        //initializing values to 0
        for(i = 0; i<=n ; i++)
            for(j = 0; j<= m ; j++)
                dp[i][j] = 0;

        Print(n,m,dp);
        cout << "\n";
        //Case 1 - if there is no persons i.e n = 0 answer will be 0
        //Case 2 - if there is no money i.e. m = 0 there is only 1 way answer will be 1
        for ( i = 1; i<= n ; i++ )
            dp[i][0] = 1;
            dp[i][i] = 1;

        Print(n,m,dp);

        for ( i = 1; i<= n ; i++){
            for ( j = 1; j<= m ; j++){
                dp[i][j] = dp[i][j-1] ;

                if(i>=j){
                    dp[i][j] += dp[i-j][j];
                }
                // else if(i==j){
                //     dp[i][j] += 1;
                // }
            }
    }

but the answers i am getting are not matching with the recursive one i don't understand what am i missing if anyone can please help me to correct i will be thankful since i have just started with dynamic programming i really am not able to figure it out

Some issues:

  • You seem to use non-local variables for your for loops. This is bad practice and can lead to errors that are difficult to debug. Instead do for (int i = 1; ...etc.

  • dp[i][i] = 1; is not part of the for loop. You would have detected this if you would have defined i only as a variable local to the for loop. It is good practice to always use braces for the body of a for loop (also if , else , ...etc), even if you would only have one statement in the body.

  • dp[i][i] = 1; is also a bad assignment: it just is not true that integerPartition(i, i) always returns 1. It happens to be true for small values of i , but not when i is greater than 3. For instance, integerPartition(4, 4) should return 5. Just remove this line.

  • In the final nested for loop you are mixing up the row/column in your dp array. Note that you had reserved the first dimension for n and the second dimension for m , so opposite to the parameter order. That is fine, but you do not stick to that decision in this for loop. Instead of dp[i][j-1] you should have written dp[i-1][j] , and instead of dp[ij][j] you should have written dp[i][ji] . And so the if condition should be adapted accordingly.

  • There is no return statement in your version, but maybe you just forgot to include it in the question. It should be return dp[n][m];

Here is the corrected code:

long long int dp[n+1][m+1];

for(int i = 0; i <=n; i++) {
    for(int j = 0; j <= m; j++) {
        dp[i][j] = 0;
    }
}

for (int i = 1; i <= n; i++) {
    dp[i][0] = 1;
}

for (int i = 1; i <= n; i++){
    for (int j = 1; j <= m ; j++) {
        dp[i][j] = dp[i-1][j];
        if (j >= i) {
            dp[i][j] += dp[i][j-i];
        }
    }
}

return dp[n][m];

Not sure that this technically is DP, but if your goal is to get the benefits of DP, memorization might be a better approach.

The idea is made up of 2 parts:

  1. At the start of each call to integerPartition , look up in a table (your dp will do nicely) to see if that computation has already been done, and if it has, just return the value stored in the table.

  2. Just before any point where integerPartition is to return a value, store it in the table.

Note that this means you don't need to try to "pivot" the original code -- it proceeds as it did originally, so you are almost guaranteed to get the same results, but without as much unnecessary re-computation (at the code of extra storage).

so, basis of your code comment, I am going to assume you only want 1 when n > 0 and m = 0 according to your recursive code, but in dp code, you interchanged them, that is i go to upto n, and j go upto m so updating your code, try to find the mistake


        // n -> no. of persons
        // m -> amount of money to be distributed
        // dp table of order (n+1)*(m+1) 
        long long int dp[n+1][m+1] ;
        //initializing values to 0
        for(i = 0; i<=n ; i++)
            for(j = 0; j<= m ; j++)
                dp[i][j] = 0;

        Print(n,m,dp);
        cout << "\n";
        //Case 1 - if there is no persons i.e n = 0 answer will be 0
        //Case 2 - if there is no money i.e. m = 0 there is only 1 way answer will be 1

        for ( i = 1; i<= n; i++){
            dp[i][0] = 0;
        }

        for(int j = 1; j <= m; j++){
            dp[0][j] = 1;
        }

        Print(n,m,dp);

        for ( i = 1; i<= n ; i++){
            for ( j = 1; j<= m ; j++){
                dp[i][j] = dp[i][j-1] ;

                if(i>=j){
                    dp[i][j] += dp[i-j][j];
                }
                // else if(i==j){
                //     dp[i][j] += 1;
                // }
            }
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM