question_id's blog

By question_id, 12 years ago, In English

Here is a problem I had been trying in Light Oj.

Problem link: http://paste.ubuntu.com/11060539/ (Since Light OJ need a user id to access)

I could solve it recursively: My solution: http://paste.ubuntu.com/11060583/

Now I want to solve it iteratively. But I am failing to do it. Please explain me how I can do this in iterative process in two dimension array like, int dp[102][10002]:: dp[n][k];

In some code I see to act like this: for(int i=0;i<=n;i++) dp[i][0]=1;

why does it fill,fill dp[i][0]?

Please I need to learn this . I am trying but failing.

Thanks in advance.

  • Vote: I like it
  • +1
  • Vote: I do not like it

»
12 years ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

The point of iterative solution is to create a state dp[current coin][current sum]. So we do the "for(int i = 0; i <= N; i++) dp[i][0]=1;" because we can make sum=0 using first i coins only 1 way (by not picking any). Then the dp[i][k] (let i be the current coin's number and k be the current sum) will be the sum of dp[i-1][k-a[i]*x] for every x such that k-a[i]*x >= 0. But even in this case the solution could get TL. As you see we calculate some things many times ( The operations to update the current states are O(K) ). We can get them just to O(1) by creating a prefix array witch is completed like that: pref[i][k] = dp[i][k] + pref[i][k-a[i]]. And then dp[i][k] = pref[i-1][k]. So at the end the time complexity will be O(N*K*T), witch will fit in TL.

  • »
    »
    12 years ago, hide # ^ |
     
    Vote: I like it +1 Vote: I do not like it

    Thanks radoslav11 . I am not getting the prefix part!!

    • »
      »
      »
      12 years ago, hide # ^ |
       
      Vote: I like it 0 Vote: I do not like it

      When you do a for loop to update the state you calculate the same thing again: dp[i][k] = dp[i-1][k-x*a[i]] for every x. But you also calculate the same thing when you calculate dp[i][k-a[i]] so you dont have to make that for loop and simply just save in the dp[i][k] = pref[i][k-a[i]] + dp[i-1][k-a[i]]. Pref array will be the sum of dp[i-1][k-x*a[i]] for every x.

»
12 years ago, hide # |
 
Vote: I like it +5 Vote: I do not like it

your recurrance is like: dp (i,j) = dp(i,j)+ dp(i+1, j—some_value) . So u can see that, value of state (i,j) depends on values of some state which are of the form ( m , k) where m=i+1 and k is less than j.

While doing iterative dp, u need to pay attention to the order in which you need the values. Here before computing state dp[i][j], you need values of dp[i+1][j-something].

You need two nested loops. If you put iteration over i in outer loop, you need to iterate from higher value of i to lower value of i, because to calculate dp[i][j], you need dp[i+1][j-something]. And if you you put iteration over j in outer loop, you need to iterate from lower value of j to higher value of j.

If you put j in outer loop, to calculate dp[i][j] you need dp[i+1][j-something], so u need values of states with lower values of j. the lowest value of j is 0, dp[i][0]=1 for all i, and dp[n+1][j] is zero for all j except 0. this is your base case. so u can do it in following way

for(int i=1;i<=n+1;i++) dp[i][0]=1; //base case
for(int j=1;j<=K;j++) dp[n+1][j]=0; //base case

for(int j=1;j<=K;j++) // j should iterate from low to high
{
  for(int i=1;i<=n;i++) // order of iteration on i does not matter here
  {
      // your calculation
      dp[i][j]=0
      for(.....)
      {
          dp[i][j]  =(dp[i][j] + dp[i+1][j- something] ) %mod;
      }

  }
}

If you put i in outer loop, to calculate dp[i][j] you need dp[i+1][j-something], so u need values of states with higher value of i. the highest value of i is n+1. so u can dot it in the following way also,

for(int i=1;i<=n+1;i++) dp[i][0]=1; //base case
for(int j=1;j<=K;j++) dp[n+1][j]=0; //base case

for(int i=n;i>=1;i--) // i should iterate from high to low
{
  for(int j=1;i<=n;i++) // order of iteration on j does not matter here
  {
     // your calculation
      dp[i][j]=0
      for(.....)
      {
          dp[i][j]  =(dp[i][j] + dp[i+1][j- something] ) %mod;
      }
  }
}

In other problems, you need to decide how to iterate over the value (from lower to higher or from higher to lower) from your recurrence. In some problems, putting one of the variables in outer loop may be more convenient than the other. You will learn from experience.

  • »
    »
    12 years ago, hide # ^ |
    ← Rev. 2  
    Vote: I like it 0 Vote: I do not like it

    But those solutions wont pass because of TL. The idea is to after making the dp table to create a prefix array because in you solution to update an array it takes O(K) time.

    It takes O(K) because of:

    for(.....)
    {
         dp[i][j]  =(dp[i][j] + dp[i+1][j- something] ) %mod;
    }
    

    You can update the state in O(1) time.

    • »
      »
      »
      12 years ago, hide # ^ |
       
      Vote: I like it 0 Vote: I do not like it

      It may get TLE, I just tried to tell how to make his code iterative. This problem is just the classic coin change problem. As you have to make K and each coin has a value of at least 1, "You can use any coin at most K times" this part makes no difference. So the innermost loop can be omitted easily. From dp[i][j] you either move to dp[i+1][j] or dp[i][j-a[i]].

  • »
    »
    12 years ago, hide # ^ |
    ← Rev. 2  
    Vote: I like it 0 Vote: I do not like it

    Thanks shopnobaj_raju... But I've implemented your idea and not getting the right output!! check my code please..

    http://paste.ubuntu.com/11065230/

    An help me more to get this!!