How can I apply memoization to this recursive function? - c++

I was solving the Subset Sum problem: "Given a set of numbers, check whether it can be partitioned into two subsets such that the sum of elements in both subsets is same or not." For this problem I created a recursive function which works correctly but I am not able to correctly memoize it.
The code is:
bool func(int a[], int i, int n, long sum) // i is 0, n is the array size, sum is required sum
{
if(sum<0||i>=n)
return 0;
if(sum==0)
return 1;
if(func(a,i+1,n,sum-a[i]))
return 1;
if(func(a,i+1,n,sum))
return 1;
return 0;
}
Please help in memoizing this code. Also can you tell that which is better for these type of problems recursive code with memoization or tabulation.

Memoization just means storing already-computed results so you don't have to recompute them later. So, whenever func calls itself and gets an answer, add an entry to a dictionary that maps func's inputs to its output. Then, before calling func, see if there's already an entry in the dictionary for the inputs you're about to use and, if so, don't call func again; instead, use the output you cached in the dictionary.

Tabulation is much easier.
bool ss(int a[],int n,int s){
bool r[n+1][s+1];
for(int i=0;i<=n;++i)
r[i][0]=true;
for(int i=1;i<=s;++i)
r[0][s]=false;
for(int i=1;i<=n;++i)
for(int j=1;j<=s;++j)
if(j>=a[i])
r[i][j]=r[i-1][j] || r[i-1][j-a[i]];
else r[i][j]=r[i-1][j];
return r[n][s];
}

Related

time complexity of (A[i]^x)>(A[i]&x)

'Is it possible to further optimize the time complexity this piece of calculation "(y^x)>(y&x)" in c++?(you are allowed to change the Boolean operation into other forms, for example this can also be written as log2(y)!=log2(x) and this gives the same Boolean output but this has a higher time complexity with c++ compiler)'enter code here
#include <bits/stdc++.h>
using namespace std;
int main() {
// your code goes here
int t;cin>>t;
while(t--){
int n;cin>>n;int A[n];
for(int i=0;i<n;i++){cin>>A[i];}
int q;cin>>q;
while(q--){
int l,r,x;
cin>>l>>r>>x;int count=0;
for(int i=l-1;i<r;i++){
if((A[i]^x)>(A[i]&x)){count++;}
}
cout<<count<<endl;
}
}
return 0;
}
'This is the code im trying to optimize.... Please help in any way possible (number of inputs cant be changed)'
(y^x)>(y&x) is equivalent to nlz(y) != nlz(x) where nlz is a function that returns the number of leading zeroes of its input.
Therefore in order to count how often (A[i]^x)>(A[i]&x) is true for items in the array A, we could make a small array N where N[j] is the number of elements with nlz(A[i]) == j in array A. Then the number of times that (A[i]^x)>(A[i]&x) is true is equivalent to n - N[nlz(x)].
That way there is no loop over A where it really matters. Creating the array N still requires a loop over A, but only once for each iteration of the outer loop, not for each individual x.
C++20 has the nlz function built in under the name std::countl_zero.

How would I print the index of an array? C++

I was just wondering how do I print off the Index position of an array? I know there's an if loop involved but I just can't seem to understand it properly.
I want the code to be able to print off what the element of the Array is and the position number. I should also mention that this is for a function as well. Any help will be appreciated. Below is my code
int index_of(string names[], int size)
{
string name;
int index;
for(int i = 0; i < size; i++)
{
if (to_lowercase (names[i]) == to_lowercase(name));
{
return;
}
}
}
What you are trying to do is called "searching".
You have a string which (potentially) is the known content of an entry in an array, but at an unknown index.
What you need to do is to find the index which, used for accessing the entry at that index, yields content which is identical to what you are looking for.
The code you show is more or less pseudo code for doing exactly that.
However, the shown code will not work for the following reasons:
it does not correctly return the index in question, it should return i;
it only returns explicitly in case of finding something, it should, after the loop, return -1;(as a proposal how to communicate failure)
it incorrectly compares (the == operator cannot meaningfully be used on "strings", which in C are only pointers to characters), it should use strncmp(), see e.g. https://en.cppreference.com/w/c/string/byte/strncmp
it does not actually print anything, but I think that is a problem of phrasing your goal and you can easily add a print outside of the shown code, using the (now hopefully correct and correctly returned) return value of the shown function
it has the problem mentioned by Nathan Pierson, see their comment/answer
This is what managed to print the indexes, you guys were actually able to help me understand what I was doing
int index_of(string names[], int size, string name)
{
for(int i = 0; i < size; i++)
{
if (to_lowercase (names[i]) == to_lowercase(name));
{
return i;
}
return -1;
}
}

Why is my variable not increasing after each recursion?

So I'm pretty new to C++ and I'm trying to generate Fibonacci numbers using recursion right? Except when I try to index to the next value I need to increase the index, and the function won't let me increase it.
How I know, is that I've run it in debug mode and stepped over the function - it continuously loops inside the fibGen function with i staying at a constant value of 1 (When I call fibGen in my main function the parameters are (startingSeq, 1, 13), where startingSeq is another vector with values {1,1}
The code builds and compiles fine, but when I run it I get a memory alloc error, which is obv caused by the infinite loop it seems to have.
What have I done wrong? Why doesn't the 'i' increase?
I've tried increasing i by having i++ inside the recursive fibGen call (in the else statement), I've tried having i++ outside the function call, and I've tried what's in there right now, where I have i+=1 and then pass i through.
Also I didn't have the 'return fibSeq' down the bottom originally because it doesn't make sense to have it there, but I put it in because vscode wouldn't compile without it in there, saying that it could never reach the end of fibGen (which makes sense now, and when this problem's fixed I think it can be removed, but at the moment it's just there so that the program will compile)
std::vector<int> fibGen(std::vector<int> fibSeq, int i, int max){
if(fibSeq[i] >= max){
return fibSeq;
}else{
fibSeq.push_back(fibSeq[i] + fibSeq[i-1]);
i+=1;
fibGen(fibSeq, i, max);
}
return fibSeq;
}
The output should be a vector containing the Fibonacci sequence, and I'm getting a mem alloc error (described above)
Actually, your code kind of works. You are just handling the vector of results sub-optimally. With your declaration:
std::vector<int> fibGen(std::vector<int> fibSeq, int i, int max)
you will always pass copies of the vector around (and you are never using the returned value). Instead, what you probably want to do is to work on the same data. To do this, use a reference to a vector (denoted by &). Then, you do not need to return anything:
void fibGen(std::vector<int>& fibSeq, int i, int max) {
if (fibSeq[i] >= max) {
return;
}
else {
fibSeq.push_back(fibSeq[i] + fibSeq[i - 1]);
i += 1;
fibGen(fibSeq, i, max);
}
}
void main(void) {
std::vector<int> fib = { 1, 1 };
fibGen(fib, 1, 34);
for (auto i : fib)
std::cout << i << std::endl;
}
So, I could not reproduce the error, until I realized that in your actual code, you were doing this instead of the code you posted:
std::vector<int> fibGen(std::vector<int> fibSeq, int i, int max){
if(fibSeq[i] >= max){
return fibSeq;
}else{
fibSeq.push_back(fibSeq[i] + fibSeq[i-1]);
i+=1;
fibGen(fibSeq, i, max);
}
}
In Visual Studio 2010, at least, it compiled fine, but threw an error at runtime, which I believe is what you described. So I'm going to assume I reproduced it.
The reason this is throwing an error is because you are invoking C++'s infamous undefined behavior. Undefined behavior in C++ permits anything to happen, like not failing to compile, but throwing a runtime error.
The fix is simple, really. You just need to return a value in all execution paths. Or, simply put, just do this:
std::vector<int> fibGen(std::vector<int> fibSeq, int i, int max){
if(fibSeq[i] >= max){
return fibSeq;
}else{
fibSeq.push_back(fibSeq[i] + fibSeq[i-1]);
i+=1;
return fibGen(fibSeq, i, max);
// Notice we are returning the value of the recursive call to fibGen().
// We can do this because we have already modified the vector the way we need to,
// so just simply returning the value is fine
}
}
Of course, you can take Nico Schertler's suggestion instead too:
void fibGen(std::vector<int>& fibSeq, int i, int max) {
if (fibSeq[i] >= max) {
return;
}
else {
fibSeq.push_back(fibSeq[i] + fibSeq[i - 1]);
i += 1;
fibGen(fibSeq, i, max);
}
}
It should be noted that not returning a value from a void function is not undefined behavior (that I'm aware), but actually how void's intended to work, so this function is fine not returning a value.

How to read matrix recursively c++

Can anyone help me with understanding recursion? I want to read a matrix recursively, and I don't really know how.
I made up a plan of transforming iterative agorithms to recursive ones in the following steps:
Repetitive structure-> if followed by recall of function somewhere in the body
Going from "top" to 0 and the going back to be alike the iterative way (i'm new to the concept, the idea may be dumb)
My function to read a matrix recursively (not working) is as follows:
void read_m(int n,int m)
{
if(n)
{
if(m)
{
read_m(n,m-1);
}
f>>v[n][m];
read_m(n-1,m);
}
}
I know what the mistake is, what I do not know is how should I solve this.
Thanks in advance.
P.S. n and m are width and height
Using recursion is probably not the greatest way to do this here but assuming you want it and you want the 'f' to execute for all the elements, it isn't going to work when n is 0 as it is inside the if(n) block.
first you should move f>>v[n][m];out if (n) block or it will not fill entire row with index 0.
second assuming that you keep data row by row you should read data before going to recursion, also to prevent double read you should only decrease rows when full column is read.
void read_m(int n,int m)
{
f>>v[width-1-n][height-1-m]; //suppose that width and height defined elsewhere
if(m)
{
read_m(n,m-1);
}
else if(n)
{
read_m(n-1,m);
}
}
if it is column by column you should change m and n in your code.
#include<fstream>
using namespace std;
ifstream f("recurs.in");
ofstream g("recurs.out");
int a[20][20],n,m;
void read(int i, int j)
{
if(j>1)
read(i,j-1);
else if(i>1)
read(i-1,j);
f>>a[i][j];
}
int main()
{
int i,j;
f>>n>>m;
read(n,m);
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
g<<a[i][j]<<' ';
g<<endl;
}
}
Working

C++ program to compute lcm of numbers between 1 to 20 (project euler )

as the title explains this is a program to find lcm of numbers between 1 to 20. i found an algorithm to do this, here's the link
http://www.cut-the-knot.org/Curriculum/Arithmetic/LCM.shtml
there is a java applet on the webpage that might explain the algorithm better
Problem: i wrote the code compiler shows no error but when i run the code the program goes berserk, i guess may be some infinite loopig but i can't figure it out for the life of me. i use turbo c++ 4.5 so basically if anyone can look at the code and help me out it would be great . thanks in advance
Algorithm:
say we need to find lcm of 2,6,8
first we find the least of the series and add to it the number above it, i.e the series become
4,6,8
now we find the least value again and add to it the intitial value in the column i.e 2
6,6,8
so the next iteration becomes
8,6,8
8,12,8
10,12,8
10,12,16
12,12,16
14,12,16
14,18,16
16,18,16
18,18,16
18,18,24
20,18,24
20,24,24
22,24,24
24,24,24
as you can see at one point all numbers become equal which is our lcm
#include<iostream.h>
/*function to check if all the elements of an array are equal*/
int equl(int a[20], int n)
{
int i=0;
while(n==1&&i<20)
{
if (a[i]==a[i+1])
n=1;
else
n=0;
i++;
}
return n;
}
/*function to calculate lcm and return that value to main function*/
int lcm()
{
int i,k,j,check=1,a[20],b[20];
/*loading both arrays with numbers from 1 to 20*/
for(i=0;i<20;i++)
{
a[i]=i+1;
b[i]=i+1;
}
check= equl(a,1);
/*actual implementation of the algorith*/
while(check==0)
{
k=a[0]; /*looks for the least value in the array*/
for(i=0;i<20;i++)
{
if(a[i+1]<k)
{
k=a[i+1]; /*find the least value*/
j=i+1; /*mark the position in array */
}
else
continue;
}
a[j]=k+b[j]; /*adding the least value with its corresponding number*/
check= equl(a,1);
}
return (a[0]);
/*at this point all numbers in the array must be same thus any value gives us the lcm*/
}
void main()
{
int l;
l=lcm();
cout<<l;
}
In this line:
a[j]=k+b[j];
You use j but it is unitialized so it's some huge value and you are outside of the array bounds and thus you get a segmentation fault.
You also have some weird things going on in your code. void main() and you use cout without either saying std::cout or using namespace std; or something similar. An odd practice.
Also don't you think you should pass the arrays as arguments if you're going to make lcm() a function? That is int lcm(int a[], int b[]);.
You might look into using a debugger also and improving your coding practices. I found this error within 30 seconds of pasting your code into the compiler with the help of the debugger.
Your loop condition is:
while(n==1&&i<20)
So your equl function will never return 1 because if n happens to be 1 then the loop will just keep going and never return a 1.
However, your program still does not appear to return the correct result. You can split the piece of your code that finds the minimum element and replace it with this for cleanliness:
int least(int a[], int size){
int minPos = 0;
for(int i=0; i<size ;i++){
if (a[i] < a[minPos] ){
minPos = i;
}
}
return minPos;
}
Then you can call it by saying j = least(a, 20);. I will leave further work on your program to you. Consider calling your variables something meaningful instead of i,j,k,a,b.
Your equl function is using array indices from 0-20, but the arrays only have 1-19
j in lcm() is uninitialized if the first element is the smallest. It should be set to 0 at the top of the while loop
In the following code, when i=19, you are accessing a[20], which is out of the bounds of the array. Should be for(i=0;i<19;i++)
for(i=0;i<20;i++) {
if(a[i+1]<k)
You are not actually using the std namespace for the cout. this should be std::cout<<l
Your are including iostream.h. The standard is iostream without the .h, this may not work on such an old compiler tho
instead of hard-coding 20 everywhere, you should use a #define. This is not an error, just a style thing.
The following code does nothing. This is the default behavior
else
continue;