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

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[i-j][j] you should have
written dp[i][j-i]. 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:
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.
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;
// }
}
}

Related

Coin making problem in DP - getting wrong answer using 2dimensional memo table

When I am passing this Input I am getting wrong answer
coin[] = {5,6}
Amount(W) = 10
my answer = 1
Correct Answer should be 2 i.e {5,5}
void coin_make(int W, vector<int> coin){
int n = coin.size();
int dp[n+1][W+1];
for(int i = 0; i <=W; i++){
dp[0][i] = INT_MAX;
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= W; j++){
if(coin[i-1] == j){
dp[i][j] = 1;
}
else if(coin[i-1] > j){
dp[i][j] = dp[i-1][j];
}
else {
dp[i][j] = min(dp[i-1][j],
1 + dp[i][j-coin[i-1]]);
}
}
}
cout<<dp[n][W];}
You're overflowing on dp[1][6], since you try to calculate 1 + INT_MAX. This error propagates further and finally the answer is not correct. When I ran it on my machine, I got -2147483648. You should use some other constant as "infinity" to prevent overflows (e.g. 2e9 (or -1, but this would require some additional if statements)). Then the code will work fine on your provided test case.

What AI technique or something else should I use on this logic problem?

for didactic purposes I'm trying to complete this challenge:
A random 3 digit number is generated (1-9) the Char sequence is DESC, for exemple "123" is a invalid number generated cause 1 > 2 and 2 > 3;
"321" is valid.
when you try to guess the number it returns C for correct Char in exact placement and N for correct Char in wrong placement, eg:
randomly generated "961"
algorithm try "321" and XPTO returns C = 1 and N = 0
algorithm try "654" and XPTO returns C = 0 and N = 1
The objective is get C=3 efficiently with less tries as possible, don't even know what kind of AI technique I need to learn about, Any tip or recommendation?
After the hint of #juvian I built an js solution
First create a List:
function generateList(){
List = new Array();
for (i = 1; i <= 7; i++) {
for (j = i+1; j <= 8; j++) {
for (k = j+1; k <= 9; k++) {
List.push(""+k+j+i);}}}
WriteResult(List.length,List[0]);
}
Then make the tests and exclude from List the "not possible" combinations
for( var i = List.length-1; i >= 0; i--){
var C = Number(document.getElementById("C").value);
var N = Number(document.getElementById("N").value);
var Guess = ""+Number(document.getElementById("Guess").value);
var CountC = 0
var CountN = 0
for( var j = 0; j < 3; j++)
{
if (Guess.substr(j, 1) == List[i].substr(j, 1)) {CountC++;}
else if (List[i].split(Guess.substr(j, 1)).length > 1) {CountN++;}
}
console.log(List[i]+" C:"+CountC+" N:"+CountN);
if (CountC != C || CountN != N) {List.splice(i, 1); }
}
WriteResult(List.length,List[0]);
}

select k values at time and flip them, find minimum cost to make all array values same equal to 1

Given a array containing only 0 and 1 and a integer value k.
You should choose k digits at time and flip all of them. Find minimum cost for making all values same. If it is not possible then give -1.
This is a simple greedy problem. I am assuming you can't flip less than k digits any time.
Find minimum cost for making all values same.
To solve this, first we will try to make all values 1 and then we'll try to make all values 0. Between these, which will take minimum steps will be our answer.
Here is my pseudo-code. The pseudo-code is self-explanatory and that's why I am not adding explanation. I am giving code for making all values 1, hope you can do for both.
int cnt = 0;
for(int i = 0; i < arr.length() - k + 1; i++) {
if(arr[i] == '1') {
continue;
}
for(int j = 0; j < k; j++) {
arr[i + j] = (arr[i + j] == '0') ? '1' : '0';
}
cnt++;
}
bool flag = true;
for(int i = 0; i < arr.length(); i++) {
if(arr[i] == '0') {
flag = false;
break;
}
}
if(flag) {
print(cnt);
} else {
print("-1");
}

How do for loops work in C? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
In the following for loop, how does the flow of control work?
int k = 0, x = 7, n = 5;
for (int i = 0; i < x; i++) {
/* When j == 4 in first cycle, k == 5 */
for (j = 0; j < n; j++) {
b[i][j] = a[k];
k++;
}
i++; // i is 2 here.
for (m = j; m >= 0; m--) {
b[i][m] = a[k];
k++;
}
}
First of all, x and n never change, so let's put their values in the for loops and remove them from the code, to make it easier to understand.
int k = 0;
for (int i = 0; i < 7; i++) {
for (int j = 0; j < 5; j++) {
b[i][j] = a[k];
k++;
}
i++;
for (int m = j; m >= 0; m--) {
b[i][m] = a[k];
k++;
}
}
• Before first iteration of the i loop
i = 0;
k = 0;
j loop goes from 0 .. 4
b[0][0] = a[0]; // b[i][j] = a[k]
b[0][1] = a[1];
b[0][2] = a[2];
b[0][3] = a[3];
b[0][4] = a[4];
j loop exits because j has reached 5.
k is same as j (starts at 0, incremented like j)
i is incremented to become 1
m loop goes from 5 .. 0
b[1][5] = a[5]; // b[i][m] = a[k]
b[1][4] = a[6];
b[1][3] = a[7];
b[1][2] = a[8];
b[1][1] = a[9];
b[1][0] = a[10];
m loop exits with
m = -1;
k = 11;
• At 2nd iteration of i loop:
i = 2; (because i *for* loop increments it)
k = 11;
j loop goes from 0 .. 4
b[2][0] = a[11]; // b[i][j] = a[k]
b[2][1] = a[12];
b[2][2] = a[13];
b[2][3] = a[14];
b[2][4] = a[15];
j loop exits because j has reached 5.
k = 16;
i is incremented to become 3
m loop goes from 5 .. 0
b[3][5] = a[16]; // b[i][m] = a[k]
b[3][4] = a[17];
b[3][3] = a[18];
b[3][2] = a[19];
b[3][1] = a[20];
b[3][0] = a[21];
.
.
.
I believe that for nested loops, the order of execution of statements follows this general form (starting from zero)
for (zero; one; ) {
two;
three;
four;
five;
for (six; seven; ten) {
eight;
nine;
}
}
Then in the second round
for (zero; twelve; eleven ) {
thirteen;
fourteen;
fifteen;
sixteen;
for (six; seventeen; twenty) {
eighteen;
nineteen;
}
}
second for loop tries to set the first row with a[k].
third for loop tries to set the second row with a[k].
The second for loop is going from j0 to jn-1 and the third for loop is going from jn to j1.
Kind of setting the rows in spiral fashion.

Distinct Subsequences DP explanation

From LeetCode
Given a string S and a string T, count the number of distinct
subsequences of T in S.
A subsequence of a string is a new string which is formed from the
original string by deleting some (can be none) of the characters
without disturbing the relative positions of the remaining characters.
(ie, "ACE" is a subsequence of "ABCDE" while "AEC" is not).
Here is an example: S = "rabbbit", T = "rabbit"
Return 3.
I see a very good DP solution, however, I have hard time to understand it, anybody can explain how this dp works?
int numDistinct(string S, string T) {
vector<int> f(T.size()+1);
//set the last size to 1.
f[T.size()]=1;
for(int i=S.size()-1; i>=0; --i){
for(int j=0; j<T.size(); ++j){
f[j]+=(S[i]==T[j])*f[j+1];
printf("%d\t", f[j] );
}
cout<<"\n";
}
return f[0];
}
First, try to solve the problem yourself to come up with a naive implementation:
Let's say that S.length = m and T.length = n. Let's write S{i} for the substring of S starting at i. For example, if S = "abcde", S{0} = "abcde", S{4} = "e", and S{5} = "". We use a similar definition for T.
Let N[i][j] be the distinct subsequences for S{i} and T{j}. We are interested in N[0][0] (because those are both full strings).
There are two easy cases: N[i][n] for any i and N[m][j] for j<n. How many subsequences are there for "" in some string S? Exactly 1. How many for some T in ""? Only 0.
Now, given some arbitrary i and j, we need to find a recursive formula. There are two cases.
If S[i] != T[j], we know that N[i][j] = N[i+1][j] (I hope you can verify this for yourself, I aim to explain the cryptic algorithm above in detail, not this naive version).
If S[i] = T[j], we have a choice. We can either 'match' these characters and go on with the next characters of both S and T, or we can ignore the match (as in the case that S[i] != T[j]). Since we have both choices, we need to add the counts there: N[i][j] = N[i+1][j] + N[i+1][j+1].
In order to find N[0][0] using dynamic programming, we need to fill the N table. We first need to set the boundary of the table:
N[m][j] = 0, for 0 <= j < n
N[i][n] = 1, for 0 <= i <= m
Because of the dependencies in the recursive relation, we can fill the rest of the table looping i backwards and j forwards:
for (int i = m-1; i >= 0; i--) {
for (int j = 0; j < n; j++) {
if (S[i] == T[j]) {
N[i][j] = N[i+1][j] + N[i+1][j+1];
} else {
N[i][j] = N[i+1][j];
}
}
}
We can now use the most important trick of the algorithm: we can use a 1-dimensional array f, with the invariant in the outer loop: f = N[i+1]; This is possible because of the way the table is filled. If we apply this to my algorithm, this gives:
f[j] = 0, for 0 <= j < n
f[n] = 1
for (int i = m-1; i >= 0; i--) {
for (int j = 0; j < n; j++) {
if (S[i] == T[j]) {
f[j] = f[j] + f[j+1];
} else {
f[j] = f[j];
}
}
}
We're almost at the algorithm you gave. First of all, we don't need to initialize f[j] = 0. Second, we don't need assignments of the type f[j] = f[j].
Since this is C++ code, we can rewrite the snippet
if (S[i] == T[j]) {
f[j] += f[j+1];
}
to
f[j] += (S[i] == T[j]) * f[j+1];
and that's all. This yields the algorithm:
f[n] = 1
for (int i = m-1; i >= 0; i--) {
for (int j = 0; j < n; j++) {
f[j] += (S[i] == T[j]) * f[j+1];
}
}
I think the answer is wonderful, but something may be not correct.
I think we should iterate backwards over i and j. Then we change to array N to array f, we looping j forwards for not overlapping the result last got.
for (int i = m-1; i >= 0; i--) {
for (int j = 0; j < n; j++) {
if (S[i] == T[j]) {
N[i][j] = N[i+1][j] + N[i+1][j+1];
} else {
N[i][j] = N[i+1][j];
}
}
}

Resources