CS50 greedy algorithm - c

I just started C programming with cs50.
I tried to do the problem set about the greedy algorithm but can't seem to find the bug. My code is below.
#include <cs50.h>
#include <stdio.h>
#include <math.h>
int main (void)
{
int count = 0;
printf("how much is the change?: ");
float change = get_float();
while(change < 0)
{
printf("change is to be more than 0");
change = get_float();
}
int amount = lroundf(change*100);
while(amount > 0)
{
if ((amount-25) >= 25)
{
amount = amount - 25;
count++;
}
else if ((amount-10) >= 10)
{
amount = amount - 10;
count++;
}
else if ((amount-5) >= 5)
{
amount = amount -5;
count++;
}
else if((amount-1) >= 1)
{
amount = amount -1;
count ++;
break;
}
else
{
printf("you have no change \n");
}
}
printf("your number of coins is %i\n", count);
}
When I input my change as 1, I am given back 8 coins. Can't seem to find where the bug is. Can anyone help me?

Firstly, you could try running your program with values for change that return simple answers, like 1 coin, using, for example, change = 0.25. If that works, then you should start trying with some few coins, repeating one type, like you did with 1.00, or joining a few types, like 0.06 . And after that, try big numbers and values with higher floating inaccuracy, like 4.10. Following this should lead you to your answers.
If, after trying that, you still can't find the problem, then here is the answer: the problem is with the if/else if expressions. When you are trying to count the quarters, for example, the (amount-25) >= 25 doesn't work properly. You're trying to take away a quarter while amount is bigger or equal to 25, but your code just do that until it gets to less than 50. Developing your expression may help you see it: (amount-25) >= 25 -> (amount-25) + 25 >= 25 + 25 -> amount >= 50.
Another problem you may find is with that break statement. It might get out from the loop earlier than expected. If you try running numbers like 0.04 and 0.03 you'll see the count stuck at 1. After removing the first penny, the code breaks out of the loop leaving amount still bigger than 0. breaks make it harder to see when the code is getting out of the loop and that's why many programmers recommend avoiding it whenever possible.

Related

Check 50 Error in Cash App for CS50 Harvard

Very new to coding, so any help is appreciated, been stuck on these check errors for a while.
//source codde
#include <stdio.h>
#include <cs50.h>
#include <unistd.h>
int main(void)
{
float user;
int change, coins, decimals;
do
{
printf("Enter change amount\n");
user = get_float("");
} while (user <= 0);
change = user * 100;
coins = 0;
while (change >= 25)
{
change = change - 25;
coins++;
}
while (change >= 10)
{
change = change - 10;
coins++;
}
while (change >= 5)
{
change = change - 5;
coins++;
}
while (change >= 1)
{
change = change - 1;
coins++;
}
printf("You have entered\f%.1f\n", user);
sleep(1);
printf("The least amount of coins possible\f%.2d\n", coins);
}
Error messages that I keep getting:
:( input of 0.01 yields output of 1
expected "1\n", not "You have enter..." this actually returns back 01 so not sure
:( input of 1.6 yields output of 7
expected "7\n", not "You have enter..." same thing just 07 is there a way to remove the zero?
:( input of 4.2 yields output of 18
expected "18\n", not "You have enter..."
did you forget to round your input to the nearest cent?
This one I'm not sure it yields an output of 22
The reason you are seeing 22 rather than 18 for the input 4.20 is because of inexactness in floating point. Floats can not represent the value 4.20 exactly, so it will store a value slightly larger, or slightly smaller than 4.20 in your variable.
In the case that a slightly smaller value is used (for instance 4.1999999 or 4.19998567), when multiplying that with 100 you get something close to 419.99999. Turning that to an int will truncate that to 419 and give you the result of 22 coins.
The solution is to round to nearest integer, rather than truncating, when turning floats to integers. A common trick which works for small floats, is to add 0.5 before truncating:
change = user * 100 + 0.5;
Values in the range 419.5000 to 420.4999 will be turned into values in the range 420.0000 to 420.99999. And truncating will then produce 420.
You could naturally also use the builtin rounding functions that comes with c.
You should also consider using double rather than float. The space saved by using float is typically not worth it on modern desktop systems.
The problem set is very clear about what kind of output the program should deliver. You are not matching that. Read again.
And don't forget to round your input, as per problem set.

Inputing a value and instead of keeping that information in a array, it changes another var

I made a program and then it didn't worked. As in the other post someone advised me to trying to debug my programs, I learned it and debugged this one. Probably it has some basic errors of writting but that's because I've changed a lot of thing recently to understand what's happening. In third time when I input a value on screen on that loop, it changes my var "i" to that value instead of keeping that number in my array "grade".
First I tried to make it all in one loop, the first one, but as always it didn't help much, and then i wrote the code by this manner as you'll see
#include <stdio.h>
#include <stdlib.h>
int main()
{
int j=0,sum=0,i=0;
int grade[]={0};
for(;j<100;j++){
printf("Type a grade:\t");
scanf("%d",&grade[j]);
if(grade[j]<10||grade[j]>20){
break;
}
}
for(;i<j;i++){
sum=sum+grade[i];
}
float average=sum/j;
printf("The average is: %.2f\n",average);
system("pause");
return 0;
}
The exercicise says that you need to read "x" grades from a student and it needs to be between 10 and 20, if the number is out of this range it stops the loop.After I just need to calculate the average os these grades.I don't really know if my var average is being calculated correctly, cause I didn't could reach over there because of my problem. If you input 11, 12 and 13 it should give to a sum of 36, but gaves me 26, i don't know how.
Erik, you should define your array in a coherent way. To allow the necessary number of elements, try defining a numeric constant. You could use it for both define the number of iterations of your cycle and the size of your grade array. You can also avoid a new cycle to calculate the sum of the array, you can do this operation while reading the grades, using only one for loop. Try this way:
#include <stdio.h>
#include <stdlib.h>
#define MAX_GRADES 100
int main()
{
int j,sum=0,i;
float average;
int grade[MAX_GRADES];
for(j = 0 ; j < MAX_GRADES; j++)
{
printf("Type a grade:\t");
scanf("%d",&i);
if ( (i<10) || (i>20) )
break;
grade[j] = i;
sum += i;
}
if (j > 0)
average = (float)sum/j;
else
average = 0;
printf("The average is: %d, %d, %.2f\n",sum, j, average);
system("pause");
return 0;
}

C - How to trace this recursion?

I've been looking at examples of recursion (in C) online in an attempt to get a better understanding of it and how it works. Generally speaking, I can trace some basic recursion problems without issue (such as a factorial problem), but I found this one and am completely lost on how to trace it.
The idea is that you have the user enter an amount of change, and by using recursion, you print out the number of ways that amount of change can be made. The code is as follows:
#include <stdio.h>
#define NUM_DENOMS 4
int ways(int amount, int denomination);
int main()
{
//Declarations & initializations
int userChange = 0;
//Get user input
printf("Enter an amount you wish to get change for (in cents):\n");// get the amount of change in from the user
scanf("%d", &userChange);
//Function call... pass user's input and denomination values (ints) as parameters
printf("%d cents can be made in %d different ways\n", userChange, ways(userChange, NUM_DENOMS));
return 0;
}
//Function to find # of ways to make change for user's amount
int ways(int amount, int denomination)
{
static int validAmounts[NUM_DENOMS] = {1, 5, 10, 25};
if(denomination<=0) //if denomination is invalid
{
return 0;
}
if((amount == 1) || (amount == 0)) //base case: only 1 combination
{
return 1;
}
else if(amount < 0) //can't have negative amount of money
{
return 0;
}
else //if denomination is valid and user's change > 1
{
return ways(amount, denomination-1) + ways(amount-validAmounts[denomination-1], denomination);
}
}
Apparently this is a common application of recursion. I can't wrap my head around how this recursion works though. What stands out to me the most is the fact that there are 2 recursive calls on the same line. I have never seen recursion applied in this way.
I did attempt to trace it but my results are definitely wrong:
Say I enter 25 as the amount of change. When I go into the ways function, none of the base cases are satisfied and so the recursion comes into play. For the first call, amount stays the same and denomination is decreased by 1, so we go back into the function with 25 and 3 (4-1) as our new arguments. None of the base cases are met until denomination is reduced to 0 (since amount never changes). At this point, we are returning 0. This is the point where I get lost. I see it that 0 gets sent back through all the previous calls and so the end result is 0, but that doesn't sound right to me. I run into the same problem when trying to trace the second call except instead of 0 getting sent back through the calls, it is 1. Obviously my perception of this recursion is horridly wrong. Can someone explain to me how this instance of recursion actually works?
One way to trace a recursive algorithm is to put a printf at the top of the recursive function. The printf should print out the arguments to the function. It's also a good idea to temporarily add more parameters to give yourself additional information about what the recursion is doing. The most common additional parameter is a depth parameter that shows how many nested calls have been made. And for this particular question (where you have two recursive calls) I would add an additional parameter to identify which call is being traced.
With that in mind, here's the modified code. I suggest starting with a simple input, like 5, to get a feel for how the recursion works.
#include <stdio.h>
#define NUM_DENOMS 4
int ways(int amount, int denomination, int left, int depth);
int main( void )
{
int userChange = 0;
printf("Enter an amount you wish to get change for (in cents):\n");
scanf("%d", &userChange);
printf("%d cents can be made in %d different ways\n", userChange, ways(userChange, NUM_DENOMS, 'M', 0));
return 0;
}
int ways(int amount, int denomination, int left, int depth)
{
static int validAmounts[NUM_DENOMS] = {1, 5, 10, 25};
printf( "%2d %d %c %2d\n", amount, denomination, left, depth );
if(denomination <= 0 || amount < 0)
return 0;
if((amount == 1) || (amount == 0))
return 1;
return ways(amount, denomination-1, 'L', depth+1) + ways(amount-validAmounts[denomination-1], denomination, 'R', depth+1);
}
The code makes two calls because it breaks the problem into two parts and each part is solved the same way. Each part is in some sense simpler than the original problem and the same method is used to solve each individual problem. As pointed out by others, there may be situations in which there are more than two parts.
You have likely seen examples with one call where one part of the problem is solved and the single recursive call solves the 'remainder' of the problem.

C prime factorization (loop failure?)

I've been looking into this simple piece of code for 1.5 hrs now and do not find the mistake. I start going crazy ;)
Could anyone of you with a fresh mind and view give me a little hint, where I might have the mistake in? (I am relatively new to C)
The problem is: The code works fine for most of the numbers I entered and tested, but accidentically I found a number that does not work: 3486118 (or 55777888 which is a multiple of it) It goes right for the first loop(s), but after factor 2 it becomes an endless loop.
Here is my code: (any help is greatly appreciated)
// Program calculates prime factors of entered number and returns them
#include <stdio.h>
int main() {
long int num, num_cp;
long int product=1;
/*prime number array up to 100.000*/
long int prime[] = {2, 3, **[...cut out MANY numbers...]** 99971, 99989, 99991};
printf("Please enter a positive integer:\n");
scanf("%li", &num);//55777888 or 3486118 not working... why?
//copy the entered number to keep the original for comparison with "product" and "break;" if equal
num_cp=num;
printf("prime factorization of %li:\n\n", num);
for (int i=0; i<sizeof(prime); i++) {
if (num_cp%prime[i]==0) {
num_cp/=prime[i];
product*=prime[i];
if (product==num) {
printf("%li\n\n", prime[i]);
break;
}
printf("%li*", prime[i]);
//If prime factor found but "product" is still not equal to "num" reset loop counter "i" to -1 (==0 in next loop)
i=-1;
}
}
printf("END");
return 0;
}
"I've been looking into this simple piece of code for 1.5 hrs now and do not find the mistake. I start going crazy ;)"
Don't. Leave it. Go away and eat a pizza. Veg out in front of your favourite movie. Have a shower. Aim for a new high-score on 2048 (or whatever). Your brain gets stuck in a rut and you are no longer seeing your code. You are only seeing what you think your code is.
When you get your brain out of the rut, then -- and only then -- go back and actually read the code you wrote. Not the code you think you wrote, but the code you actually wrote. Yes, they are different.
The prime factors of 55777888 are 2·2·2·2·2·1743059, where the last factor is too large to be contained in your list.
You can fix this in your code: When the product is equal to the product of the prime factors you have found, num_cp is 1. If num_cp is greater than one after you have exhausted your prime list, it is a factor of num. If num/num_cp is smaller than the largest prime you have checked, you can assume that the remaining value of num_cp is a prime. If it wasn't you'd have found more factors earlier.
You can fix this by adding an additional check after your main loop:
if (num_cp > 1) printf("%li\n\n", num_cp);
(If long int is a 64-bit number on your system, you're still not safe: The remaining factor might be made up of several numbers that are not in your array.)
Finally: Resetting the for loop counter so that the loop starts over isn't a good idea. It always starts from the beginning and re-checks primes that you have already checked. And it just isn't natural program flow, which makes it hard to read. A while loop instead of the inner if block would be more natural in my opinion.
Edit: To illustrate:
#include <stdio.h>
int main() {
long int num;
/* prime number array up to 100.000 */
long int prime[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31};
int nprime = sizeof(prime) / sizeof(*prime);
num = 55;
printf("%li == ", num);
for (int i = 0; i < nprime; i++) {
long int p = prime[i];
if (num <= 1) break;
while (num % p == 0) {
num /= prime[i];
printf("%li", p);
if (num > 1) printf(" * ");
}
}
if (num > 1) printf("%li", num);
printf("\n");
return 0;
}
Things to note:
Instead of resetting the main loop counter i, a while loop is used, which consumes all repetitions of the same factor. If a prime p doesn't divide the number, the while loop isn't entered, just like an if clause.
I've removed the copy of num and used num throughout, mainly to remove clutter. I've also removed the product. Your logic that all prime factors should multiply to the original number, is good. But it also works the other way round: After dividing the number by all primes, we are left with 1. And we have to divide the number anyways. By removing the product, we have to keep track of only one variable instead of two.
I've moved the break condition to the front, so we catch negative numbers and 0 early.
That said, your way to code isn't wrong, just maybe a bit unusual in places.

C Program Runs Surprisingly Slow

A simple program I wrote in C takes upwards of half an hour to run. I am surprised that C would take so long to run, because from what I can find on the internet C ( aside from C++ or Java ) is one of the faster languages.
// this is a program to find the first triangular number that is divisible by 500 factors
int main()
{
int a; // for triangular num loop
int b = 1; // limit for triangular num (1+2+3+......+b)
int c; // factor counter
int d; // divisor
int e = 1; // ends loop
long long int t = 0; // triangular number in use
while( e != 0 )
{
c = 0;
// create triangular number t
t = t + b;
b++;
// printf("%lld\n", t); // in case you want to see where it's at
// counts factors
for( d = 1 ; d != t ; d++ )
{
if( t % d == 0 )
{
c++;
}
}
// test to see if condition is met
if( c > 500 )
{
break;
}
}
printf("%lld is the first triangular number with more than 500 factors\n", t);
getchar();
return 0;
}
Granted the program runs through a lot of data, but none of it is ever saved, just tested and passed over.
I am using the Tiny C Compiler on Windows 8.
Is there a reason this runs so slowly? What would be a faster way of achieving the same result?
Thank you!
You're iterating over a ton of numbers you don't need to. By definition, a positive factor is any whole number that can be multiplied by another to obtain the desired product.
Ex: 12 = 1*12, 2*6, and 3*4
The order of multiplication are NOT considered when deciding factors. In other words,
Ex: 12 = 2*6 = 6*2
The order doesn't matter. 2 and 6 are factors once.
The square root is the one singleton that will come out of a factoring of a product that stands alone. All others are in pairs, and I hope that is clear. Given that, you can significantly speed up your code by doing the following:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
// this is a program to find the first triangular number that is divisible by 500 factors
int main()
{
int c = 0; // factor counter
long long int b = 0; // limit for triangular num (1+2+3+......+b)
long long int d; // divisor
long long int t = 0; // triangular number in use
long long int r = 0; // root of current test number
while (c <= 500)
{
c = 0;
// next triangular number
t += ++b;
// get closest root.
r = floor(sqrt(t));
// counts factors
for( d = 1 ; d < r; ++d )
{
if( t % d == 0 )
c += 2; // add the factor *pair* (there are two)
}
if (t % r == 0) // add the square root if it is applicable.
++c;
}
printf("%lld is the first triangular number with more than 500 factors\n", t);
return 0;
}
Running this on IDEOne.com takes less than two seconds to come up with the following:
Output
76576500 is the first triangular number with more than 500 factors
I hope this helps. (and I think that is the correct answer). There are certainly more efficient ways of doing this (see here for some spoilers if you're interested), but going with your code idea and seeing how far we could take it was the goal of this answer.
Finally, this finds the first number with MORE than 500 factors (i.e. 501 or more) as per your output message. Your comment at the top of the file indicates you're looking for the first number with 500-or-more, which does not match up with your output message.
Without any math analysis:
...
do
{
c = 0;
t += b;
b++;
for (d = 1; d < t; ++d)
{
if (!(t % d))
{
c++;
}
}
} while (c <= 500);
...
You are implementing an O(n^2) algorithm. It would be surprising if the code took less than a half an hour.
Refer to your computer science textbook for a better method compared to this brute force method of: check 1, 1 + 2, 1 + 2 + 3, etc.
You might be able to shorten the inner for loop. Does it really need to check all the way up to t for factors that divide the triangular number. For example, can 10 be evenly divisible by any number greater than 5? or 100 by any number greater than 50?
Thus, given a number N, what is the largest number that can evenly divide N?
Keep reading/researching this problem.
Also, as other people have mentioned, the outer loop could be simply coded as:
while (1)
{
// etc.
}
So, no need need to declare e, or a? Note, this doesn't affect the length of time, but your coding style indicates you are still learning and thus a reviewer would question everything your code does!!
You are doing some unnecessary operations, and I think those instructions are not at all required if we can check that simply.
first :
while(e!=0)
as you declared e=1, if you put only 1 in loop it will work. You are not updating value of e anywhere.
Change that and check whether it works fine or not.
One of the beautiful things about triangle numbers, is that if you have a triangle number, with a simple addition operation, you can have the next one.

Resources