SPOJ SCUBADIV - Recursive DP Approach [closed] - c++

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I have been trying to solve http://www.spoj.com/problems/SCUBADIV/ question at SPOJ. I have come up with a recursive DP solution.
I am using knapsack approach with a 3 dimensional array to store the number of cylinders, required oxygen weight, and nitrogen weight. At each recursive step I'm checking for the amount of oxygen and nitrogen yet to be filled. If it is negative, it's as good as zero.
#include<bits/stdc++.h>
using namespace std;
#define inf 99999999
int n;
vector<int> o;
vector<int> ni;
vector<int> w;
int ow;
int nw;
int knapsack(int n,int ow,int nw); // n - number of cylinders,ow-wt. of oxygen
// nw-wt. of nitogen.
int main(){
int t;
scanf("%d",&t);
while(t--){
int i;
scanf("%d %d",&ow,&nw);
scanf("%d",&n);
o.resize(n);
ni.resize(n);
w.resize(n);
for(i=0;i<n;i++)
scanf("%d%d%d",&o[i],&ni[i],&w[i]); // o[i] storing wt. of oxygen cylinders
int res = knapsack(n,ow,nw); //ni[i] storing wt. of nitrogen cylinders
printf("%d",res);
}
return 0;
}
int knapsack(int n,int ow,int nw){
int dp[n+1][ow+1][nw+1];
memset(dp,inf,sizeof (dp)); //setting value of array to inf to get minimum weight
int i;
for(i=0;i<n;i++)
dp[i][0][0]=0;
if(dp[n][ow][nw]!= inf)
return dp[n][ow][nw];
else if (ow - o[n-1]>=0 && nw - ni[n-1]>=0)
return dp[n][ow][nw]= min(knapsack(n-1,ow,nw),w[n-1]+knapsack(n-1,ow-o[n-1],nw-ni[n-1]));
else if(ow -o[n-1]<0 && nw - ni[n-1] >=0)
return dp[n][ow][nw]=min(knapsack(n-1,0,nw),w[n-1]+knapsack(n-1,0,nw-ni[n-1]));
else if(ow-o[n-1]>=0 && nw-ni[n-1]<0)
return dp[n][ow][nw]=min(knapsack(n-1,ow,0),w[n-1]+knapsack(n-1,ow-o[n-1],0));
else if(ow-o[n-1]<0 && nw-ni[n-1]<0)
return dp[n][ow][nw]= knapsack(n-1,0,0);
}
This code is not giving the desired result (it's giving -1). Is the approach correct ?

There is a problem with this code:
int dp[n+1][ow+1][nw+1];
memset(dp,inf,sizeof (dp));
The memset() function sets a byte pattern, not a value. Since inf is a larger-than-a-byte value, it is essentially doing inf % 256 and initializing all the bytes in dp[][][] to that value. This is further complicated by dp[][][] being of base type int, so 4 bytes set to the same byte value is something unexpected.
In the case of your value for inf, of 99999999, the byte value will be 0xff, and so all the ints in dp[][][] will be set to -1.
I don't know if this is expected, but it looks like it could be a mistake.

Let M(x, O, N) be the minimum weight of cylinders that will provide O liters of oxygen and N liters of nitrogen by choosing from only cylinders 1 to x. Let O(x), N(x), and W(x) be the amount of oxygen and nitrogen available in the x'th cylinder and the cylinder's weight respectively. Then either we choose to use the x'th cylinder or we don't:
M(x, O, N) = min( W(x) + M(x - 1, O - O(x), N - N(x)), M(x - 1, O, N) )
The base case occurs when we have no cylinders at all.
M(0, O, N) = 0 if O <= 0 and N <= 0, infinity otherwise
I won't be reading your unformatted, cryptically written code to figure out whether it implements this correctly. I will say memset can only be used to set bytes to a given value. Your call is not doing what you think. Additionally, your recursive procedure returns junk if execution reaches the end of the if chain.
Work a small example by hand. Run your code either in a debugger or with printfs inserted to show what's going on. Figure out where its actual execution diverges from your hand calculation.

Yes, it is possible to solve this problem with a recursive approach, but this is not how to do it. There are multiple problems with the code, and 'obviously' it will return -1. The question is I shall try to answer is: tell me some of the things wrong with this code.
Variable names like dp obscure the meaning of the code. Give them meaningful names!
Don't resize a vector and read into a pointer. Read values and push them onto the vector.
Print out the data to ensure you read it right.
The memset function fills with bytes, in this case -1. Use a loop to initialise ints.
The first if statement can only ever return 0 or -1 (or inf once you fix the init). As it is the other code will not be executed.
Assigning a value into dp is of no effect, since it is in automatic storage (on the stack).
I don't understand the chain of if statements. Explain them.
There is no else so the function can fall off the end.
Best to rewrite, debug, and if it still doesn't work come back with something we can read.

Related

Multiply numbers which are divisible by 3 and less than 10 with a while loop in c++?

In C++, I should write a program where the app detects which numbers are divisible by 3 from 1 till 10 and then multiply all of them and print the result. That means that I should multiply 3,6,9 and print only the result, which is 162, but I should do it by using a "While" loop, not just multiplying the 3 numbers with each other. How should I write the code of this? I attached my attempt to code the problem below. Thanks
#include <iostream>
using namespace std;
int main() {
int x, r;
int l;
x = 1;
r = 0;
while (x < 10 && x%3==0) {
r = (3 * x) + 3;
cout << r;
}
cin >> l;
}
Firstly your checking the condition x%3 == 0 brings you out of your while - loop right in the first iteration where x is 1. You need to check the condition inside the loop.
Since you wish to store your answer in variable r you must initialize it to 1 since the product of anything with 0 would give you 0.
Another important thing is you need to increment the value of x at each iteration i.e. to check if each number in the range of 1 to 10 is divisible by 3 or not .
int main()
{
int x, r;
int l;
x = 1;
r = 1;
while (x < 10)
{
if(x%3 == 0)
r = r*x ;
x = x + 1; //incrementing the value of x
}
cout<<r;
}
Lastly I have no idea why you have written the last cin>>l statement . Omit it if not required.
Ok so here are a few hints that hopefully help you solving this:
Your approach with two variables (x and r) outside the loop is a good starting point for this.
Like I wrote in the comments you should use *= instead of your formula (I still don't understand how it is related to the problem)
Don't check if x is dividable by 3 inside the while-check because it would lead to an too early breaking of the loop
You can delete your l variable because it has no affect at the moment ;)
Your output should also happen outside the loop, else it is done everytime the loop runs (in your case this would be 10 times)
I hope I can help ;)
EDIT: Forget about No.4. I didn't saw your comment about the non-closing console.
int main()
{
int result = 1; // "result" is better than "r"
for (int x=1; x < 10; ++x)
{
if (x%3 == 0)
result = result * x;
}
cout << result;
}
or the loop in short with some additional knowledge:
for (int x=3; x < 10; x += 3) // i know that 3 is dividable
result *= x;
or, as it is c++, and for learning purposes, you could do:
vector<int> values; // a container holding integers that will get the multiples of 3
for (int x=1; x < 10; ++x) // as usual
if ( ! x%3 ) // same as x%3 == 0
values.push_back(x); // put the newly found number in the container
// now use a function that multiplies all numbers of the container (1 is start value)
result = std::accumulate(values.begin(), values.end(), 1, multiplies<int>());
// so much fun, also get the sum (0 is the start value, no function needed as add is standard)
int sum = std::accumulate(values.begin(), values.end(), 0);
It's important to remember the difference between = and ==. = sets something to a value while == compares something to a value. You're on the right track with incrementing x and using x as a condition to check your range of numbers. When writing code I usually try and write a "pseudocode" in English to organize my steps and get my logic down. It's also wise to consider using variables that tell you what they are as opposed to just random letters. Imagine if you were coding a game and you just had letters as variables; it would be impossible to remember what is what. When you are first learning to code this really helps a lot. So with that in mind:
/*
- While x is less than 10
- check value to see if it's mod 3
- if it's mod 3 add it to a sum
- if not's mod 3 bump a counter
- After my condition is met
- print to screen pause screen
*/
Now if we flesh out that pseudocode a little more we'll get a skeletal structure.
int main()
{
int x=1//value we'll use as a counter
int sum=0//value we'll use as a sum to print out at the end
while(x<10)//condition we'll check against
{
if (x mod 3 is zero)
{
sum=x*1;
increment x
}
else
{
increment x
}
}
//screen output the sum the sum
//system pause or cin.get() use whatever your teacher gave you.
I've given you a lot to work with here you should be able to figure out what you need from this. Computer Science and programming is hard and will require a lot of work. It's important to develop good coding habits and form now as it will help you in the future. Coding is a skill like welding; the more you do it the better you'll get. I often refer to it as the "Blue Collar Science" because it's really a skillset and not just raw knowledge. It's not like studying history or Biology (minus Biology labs) because those require you to learn things and loosely apply them whereas programming requires you to actually build something. It's like welding or plumbing in my opinion.
Additionally when you come to sites like these try and read up how things should be posted and try and seek the "logic" behind the answer and come up with it on your own as opposed to asking for the answer. People will be more inclined to help you if they think you're working for something instead of asking for a handout (not saying you are, just some advice). Additionally take the attitude these guys give you with a grain of salt, Computer Scientists aren't known to be the worlds most personable people. =) Good luck.

Printing a value changes the output of the code

Few hours ago, a competition was held on CodeForces , this was one the questions of the competition -
Problem C (You dont have to read/solve it to answer the question)
EDIT : Adding the question here as requested, again, one does not necessarily have to read it.
Slastyona and her loyal dog Pushok are playing a meaningless game that
is indeed very interesting.
The game consists of multiple rounds. Its rules are very simple: in
each round, a natural number k is chosen. Then, the one who says (or
barks) it faster than the other wins the round. After that, the
winner's score is multiplied by k2, and the loser's score is
multiplied by k. In the beginning of the game, both Slastyona and
Pushok have scores equal to one.
Unfortunately, Slastyona had lost her notepad where the history of all
n games was recorded. She managed to recall the final results for each
games, though, but all of her memories of them are vague. Help
Slastyona verify their correctness, or, to put it another way, for
each given pair of scores determine whether it was possible for a game
to finish with such result or not.
Input In the first string, the number of games n (1 ≤ n ≤ 350000) is
given.
Each game is represented by a pair of scores a, b (1 ≤ a, b ≤ 10^9) –
the results of Slastyona and Pushok, correspondingly.
Output For each pair of scores, answer "Yes" if it's possible for a
game to finish with given score, and "No" otherwise.
You can output each letter in arbitrary case (upper or lower).
So I solved it, and after the competition was over, me and my friends were discussing the problems when they asked me what was my answer coming for the following test case -
1
1 1
I said it was "Yes" on my IDE (Dev-C++ 5.11), (as it was supposed to be)
But when we ran it on ideone, it came out to be "No" !!
I thought there must be a problem with my code only, so i tried debugging it when i came across this problem,
My Code -
#include<stdio.h>
using namespace std;
long long int iscube(long long int n)
{
long long int lo = 0;
long long int hi = 1000000;
while(lo < hi)
{
long long int mid = (lo+hi)/2;
if(mid*mid*mid < n)
lo = mid+1;
else
hi = mid;
}
return lo;
}
int main()
{
long long int a,b;
int n;
scanf("%d",&n);
while(n--)
{
scanf("%I64d %I64d",&a,&b);
long long int c = a*b;
long long int cb = iscube(c);
//printf("%lld",cb)
if(cb*cb*cb == c)
{
if(a%cb == 0 && b%cb == 0)
printf("Yes\n");
else
printf("No\n");
continue;
}
printf("No\n");
}
}
When i give the input as
1
1 1
in the above code, the answer comes out to be "No"
BUT if I ONLY uncomment the line above the if statement in the while loop in the main() function,
the answer would be "1 Yes"
(these outputs are the outputs i got when i ran the code on ideone, when running on Dev-C++ 5.11 , i got "Yes" and "1 Yes" as expected)
Now while i was thinking that my my answer of codeforces would be evaluated as WA, After the system test, it came out to be Accepted!
Does anyone have any idea on why this issue is arising?
(Also, could someone add the appropriate tags, if any)
Turn up your warnings, you have undefined behavior in your scanf:
warning: length modifier 'I64' results in undefined behavior or no effect with 'd' conversion specifier [-Wformat]
scanf("%I64d %I64d",&a,&b);
If you change it to scanf("%lld %lld",&a,&b); (C++11), then you'll have defined behavior, however since you're using C++, just use a stream instead:
std::cin >> a >> b;
Demo

Finding the square of a number without multiplication [duplicate]

This question already has answers here:
Making a square() function without x*x in C++
(7 answers)
Closed 4 years ago.
I'm a beginner in programming and trying to learn C++ by the book Programming principles and practice using C++. In some parts of the book there are little exercises that you can try to do, one of this exercises is about calculating the square of a number, here is what my book says :
Implement square() without using the multiply operator, that is, do the x * x by repetead addition (start a variable result to 0 and add x to it x times).
I've already found a solution for this program but my first tentative was something like this :
#include <iostream>
int main()
{
int a = 0;
std::cout << "Enter an integer value : ";
std::cin >> a;
while (a < a * a)
{
a += a;
std::cout << a << "\n";
}
}
I know this code is wrong but I can't understand the output of the progam, if I enter 5 the program prints 10 20 30 40 50 until 8000, why the for loop doesn't stop when a is greater than its square ? I'm just curious to undersant why
Using multiplication when trying to avoid multiplication seems broken. What about this:
int r = 0;
for (int n = 0; n < a; ++n) {
r += a;
}
why the for loop doesn't stop when a is greater than its square ?
Because it never is. If you compare the graph of y=x^2 against the graph of y=x, you will see that the only time y=x is above, is when 0 < x < 1. That's never the case for integers1. Now, since we're talking about computers with limited storage here, there is a thing called overflow, which will cause a very large number to become a very small number. However, signed integer overflow is undefined behavior in C++. So once your loop gets to the point where overflow would happen, you cannot rely on the results.
1. Note that your loop is not set to stop just when a is greater than its square, but when it is greater than or equal to its square. So, your loop will actually stop if a is 0 or 1.

Time Limit Exceeded - Simple Program - Divisibility Test

Input
The input begins with two positive integers n k (n, k<=10^7). The next n lines of input contain one positive integer ti, not greater than 10^9, each.
Output
Write a single integer to output, denoting how many integers ti are divisible by k.
Example
Input:
7 3
1
51
966369
7
9
999996
11
Output:
4
My Code:
#include <iostream>
using namespace std;
int main()
{
long long n,k, i;
cin>>n;
cin>>k;
int count=0;
for(i=0;i<n;i++)
{
int z;
cin>>z;
if(z%k == 0) count++;
}
cout<<count;
return 0;
}
Now this code produces the correct output. However, its not being accepted by CodeChef(http://www.codechef.com/problems/INTEST) for the following reason: Time Limit Exceeded. How can this be further optimized?
As said by caleb the problem is labeled "Enormous Input Test" so it requires you to use some better/faster I/O methods
just replacing cout with printf and cin with scanf will give you an AC but to improve your execution time you need to use some faster IO method for example reading character by character using getchar_unlocked() will give you a better execution time
so you can read the values by using a function like this , for a better execution time.
inline int read(){
char c=getchar_unlocked();
int n=0;
while(!(c>='0' && c<='9'))
c=getchar_unlocked();
while(c>='0' && c<='9'){
n=n*10 + (c-'0');
c=getchar_unlocked();
}
return n;
}
The linked problem contains the following description:
The purpose of this problem is to verify whether the method you are
using to read input data is sufficiently fast to handle problems
branded with the enormous Input/Output warning. You are expected to be
able to process at least 2.5MB of input data per second at runtime.
Considering that, reading values from input a few bytes at a time using iostreams isn't going to cut it. I googled around a bit and found a drop-in replacement for cin and cout described on CodeChef. Some other approaches you could try include using a memory-mapped file and using stdio.
It might also help to look for ways to optimize the calculation. For example, if ti < k, then you know that k is not a factor of ti. Depending on the magnitude of k and the distribution of ti values, that observation alone could save a lot of time.
Remember: the fact that your code is short doesn't mean that it's fast.

How do I convert this function into a loop?

I have an array of letters of an unknown number of elements which contains lower case letters. I have written a function for converting a lower case number to its ASCII value
int returnVal (char x)
{
return (int) x;
}
I am trying to combine all of these values into one number. Subtracting 87 from each of these means that the value is always a 2 digit number. I am able to combine an array made up if two elements by:
returnVal (foo[0]) - 87) + returnVal (foo[1] - 87) * 100
an array made up of three elements by
returnVal (foo[0]) - 87) + returnVal (foo[1] -87) * 100 + returnVal (foo[2] - 87) * 100 * 100
I am multiplying each element by 100^its position in the array and summing them. This means that [a,b,c] would become 121110 (yes, the 'flip' having the value for 'c' first and 'a' last is intentional). Could anybody programme this (for an array of an unknown number of elements)?
EDIT: I have received no form of schooling at programming/computer science at any pojnt in my life, this is not homework. I am trying to teach myself and I have got stuck; I don't know anybody in person who I could go to for help so I asked here, apologies to those of you who are offended.
EDIT2: I know that this opinion is going to annoy a lot of people; what is the purpose of stackoverflow.com if it is not to exchange information? If I were a child who was stuck with my homework (I'm not) surely that is a valid reason for using stack overflow? Many people on this website seem to have the mindset that if a problem is asked by a beginner then it is not worth answering, which is completely fine because your time is your own. However, what genuinely bugs me is the people who see a question which they deem trivial and say "homework" and vote it down immediately. I think that this website would be far better if there wasn't an "minimum-level" knowledge required in order to ask questions, the "elitist" mindset is just childish in my opinion.
Since this is a learning exercise, here are some hints for you to complete the task yourself:
Prepare a value that will server as the "running total" for your number so far.
Start the running total at zero.
When you convert a number, say, "1234", to an int, this value would first become 1, then 12, then 123, and finally 1234
The final value of the running total is your end result
To go from a previous value to the next, multiply the prior value by ten, and add the value of the current digit to it
Your returnVal does not make sense, because in C you can very often avoid an explicit conversion of char to int. You can definitely avoid it in this case.
Making a function int digit(char c) that returns a value of decimal digit, i.e. c-'a', would be a lot more useful, because it would let you get rid of your c-87 in multiple spots.
char array[SIZE];
long factor=1;
long result=0;
for(int i=0; i<SIZE; i++)
{
result+=returnVal(foo[i])-87)*factor;
factor*=100;
}
This should work for as long as long is large enough to hold the value of 100^the position and, of course, as long as the result does not overflow.