Coin change problem in C++ stuck on recursion - c++

I have to write a recursiive solution to the coin change problem in C++.
The problem provides a set of coins of different values and a value representing a sum to be paid.
The problem asks to provide the number of ways in which the sum can be paid given the coinages at hand.
I am stuck on this:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
long recursive(int amount, vector<long>& input_vector, long ways, vector<long>::const_iterator current) {
if (amount < 0)
return ways;
for (auto iter = current; iter != input_vector.end(); ++iter) {
cout << "amount: " << amount << ", current coin: " << *iter << '\n';
ways += recursive(amount - *iter, input_vector, 0, iter);
cout << "ways: " << ways << '\n';
}
return ways;
}
long getWays(int n, vector<long> c) {
sort(c.begin(), c.end(), greater<long>());
return recursive(n, c, 0, c.begin());
}
int main() {
int amount = 32;
vector<long> coinages = {2, 5, 6, 10};
cout << "Solution is: " << getWays(amount, coinages) << endl;
return 0;
}
The answer should be 27, but I get 0?
Even if I omit the eturn 0 at the end of the main program, I still get 0.
So I'm kind of frustrated my logic does not work here and I'm clueless about how to solve this in a different way.

If amount is 0, this is an answer, return 1 to be added to ways. If you got below 0, dead end street, return 0, nothing will be added.
if (amount == 0)
return 1;
if (amount < 0)
return 0;

Related

C++ code - problems with сode execution time

there is code.
#include "pch.h"
#include <algorithm>
#include <iostream>
#include <vector>
#include <stdlib.h>
using namespace std;
vector<int> SearchInt(vector<int> vec, int num) {
vector<int> temp(2);
sort(begin(vec), end(vec));
int j = 0;
for (int i : vec) {
if (i > num) {
temp[0] = i;
temp[1] = j;
return { temp };
}
//cout << i << " !>= " << num << endl ;
j++;
}
cout << "NO";
exit(0);
}
int main()
{
int n;
cin >> n;
vector<int> nums(n, 0);
vector<int> NewNums(n, 0);
for (int i = 0; i < n; i++) {
cin >> nums[i];
}
if (n != nums.size()) {
cout << "://";
return 0;
}
sort(begin(nums), end(nums));
NewNums[1] = nums[nums.size() - 1];
nums.erase(nums.begin() + nums.size() - 1);
NewNums[0] = nums[nums.size() - 1];
nums.erase(nums.begin() + nums.size() - 1);
for (int j = 2; j <= NewNums.size() - 1; j++) {
NewNums[j] = SearchInt(nums, NewNums[j-1]- NewNums[j-2])[0];
nums.erase(nums.begin() + SearchInt(nums, NewNums[j] - NewNums[j - 1])[1]);
}
if (NewNums[NewNums.size()-1] < NewNums[NewNums.size() - 2] + NewNums[0]) {
cout << "YES" << endl;
for (int i : NewNums) {
cout << i << " ";
}
return 0;
}
else {
cout << "NO";
return 0;
}
}
His task is to check whether it is possible from the given Each number is less than the sum of the two adjacent ones.
(each number is less than both of two adjacent ones)
But there is a problem - with a large number of numbers, the code takes too long. Please help me to optimize it, or just give some advice.
numbers cаn not be null.
time limit: 3.0 s
n <= 500000
You are given n numbers a1, a2,…, an. Is it possible to arrange them in a circle so that each number is strictly less than the sum of its neighbors?
For example, for the array [1,4,5,6,7,8], the left array satisfies the condition, while the right array does not, since 5≥4 + 1 and 8> 1 + 6.
Input data
The first line contains one integer n (3≤n≤105) - the number of numbers.
The second line contains n integers a1, a2,…, an (1≤ai≤109) - the numbers themselves. The given numbers are not necessarily different.
Output
If there is no solution, print "NO" on the first line.
If it exists, print "YES" on the first line. After that, on the second line print n numbers - the elements of the array in the order in which they will stand on the circle. The first and last elements you print are considered neighbors on the circle. If there are multiple solutions, output any of them. You can print a circle starting with any of the numbers.
First I'll only briefly analyze technical shortcomings of your code - without analyzing its meaning. After that I'll write my solution of the problem you defined.
Performance problems of your code are due to some strange decisions:
(1) passing std::vector<int> by value and not by reference to SearchInt function - this implies allocating and copying of the whole array on each function invocation,
(2) call SearchInt two times per loop iteration in function main instead of only one,
(3) sort array within each invocation of SearchInt - it is already sorted before the loop.
To be honest your code feels ridiculously time-consuming. I'm only wondering if that was your intention to make it as slow as you possibly can...
I will not analyze correctness of your code according to problem description. To be honest even after fixing technical shortcomings your code seems to me utterly sub-optimal and quite incomprehensible - so it is just easier to solve the problem from scratch to me.
The answer to the problem as defined is YES if the biggest number is smaller than the sum of the second big and the third big and NO otherwise - this follows from the fact that all numbers are positive (in range 1 - 109 according to newly found problem description). If the answer is YES then to make a circle that satisfies the problem description you just need in a sorted sequence of input numbers switch places of the biggest number and the next big one - that's all.
Here is my code for that (for slightly relaxed input format - I'm not checking if number of items is on a separate line and that all items are on the same line - but all correct inputs will be parsed just fine):
#include <set>
#include <iostream>
int main()
{
std::multiset<unsigned> input_set;
unsigned n;
if( !( std::cin >> n ) )
{
std::cerr << "Input error - failed to read number of items." << std::endl;
return 2;
}
if( n - 3U > 105U - 3U )
{
std::cerr << "Wrong number of items value - " << n << " (must be 3 to 105)" << std::endl;
return 2;
}
for( unsigned j = 0; j < n; ++j )
{
unsigned x;
if( !( std::cin >> x ) )
{
std::cerr << "Input error - failed to read item #" << j << std::endl;
return 2;
}
if( x - 1U > 109U - 1U )
{
std::cerr << "Wrong item #" << j << " value - " << x << " (must be 1 to 109)" << std::endl;
return 2;
}
input_set.insert(x);
}
std::multiset<unsigned>::const_reverse_iterator it = input_set.rbegin();
std::multiset<unsigned>::const_reverse_iterator it0 = it;
std::multiset<unsigned>::const_reverse_iterator it1 = ++it;
if( *it0 >= *it1 + *++it )
{
std::cout << "NO (the biggest number is bigger than the sum of the second big and the third big numbers)" << std::endl;
return 1;
}
std::cout << "YES" << std::endl;
std::cout << "Circle: " << *it1 << ' ' << *it0;
do
{
std::cout << ' ' << *it;
}
while( ++it != input_set.rend() );
std::cout << std::endl;
return 0;
}

How do I generate any random number UNDER or ABOVE a certain number in C++?

For example, I'm making a guessing game. If the computer guesses too low, I want to send it to this function
int player1::guessLow(int g)
{
return rand() % guess + 1;
}
So that it guesses any number ABOVE what it just guessed. I also want to do the same for when it's too high
int player1::guessHigh(int g)
{
return rand() % guess - 1;
}
Obviously this isn't the correct code but how would I do this? The < and > operators don't work between in front of guess. I'm trying to come up with any random number and help the computer remember so it keeps guessing below or above that number. How would I accomplish this? Is there an algorithm or template that I can use?
UPDATE:
Here is the code
bool checkForWin(int guess, int answer)
{
cout << "You guessed " << guess << ". ";
if (answer == guess)
{
cout << "You're right! You win!" << endl;
return true;
}
else if (answer < guess)
cout << "Your guess is too high." << endl;
else
cout << "Your guess is too low." << endl;
return false;
}
void play(Player &player1, Player &player2)
{
int answer = 0, guess = 0;
answer = rand() % 100;
bool win = false;
while (!win)
{
cout << "Player 1's turn to guess." << endl;
guess = player1.getGuess();
win = checkForWin(guess, answer);
if (win) return;
cout << "Player 2's turn to guess." << endl;
guess = player2.getGuess();
win = checkForWin(guess, answer);
}
}
There are many examples of generating a random number in a given range using the standard C++ facilities. Here is a little thread-safe function to get you a number in a range:
#include <chrono>
#include <iostream>
#include <random>
long random( long min, long max )
{
// Create and initialize our PRNG
thread_local auto seed = std::chrono::system_clock::now().time_since_epoch().count();
thread_local std::ranlux48 prng( seed );
return std::uniform_int_distribution <long> ( min, max )( prng );
}
(If you are only single-threaded, you can replace thread_local with static.)
To get a range only bounded by minimum or maximum, use numeric_limits<> to find the lowest/highest value to bound with:
#include <limits>
int main()
{
std::cout << "Maximum value of 12: " << random( std::numeric_limits <long> ::min(), 12 ) << "\n";
}
Hope this helps.
rand() is part of C++ (at least for now) and is fine for a simple guessing game.
In some cases srand may not be appropriate, for example I might want repetitive behavior and predictability for testing purposes.
For this problem you may wish to use srand otherwise the guessing game gets boring.
You should completely avoid rand in many applications such as cryptography.
But here the issue is more basic. You don't need to keep track of all the numbers which you have guessed. You just have to keep track of minimum and maximum range. Example:
#include <iostream>
#include <ctime>
#include <cstdlib>
using std::cout;
int main()
{
srand((unsigned int)time(NULL));
int guess = rand();
int min = 0;
int max = RAND_MAX;
while(true)
{
int n = min + rand() % (max - min);
//(n goes up to max, not including max)
if(n < guess)
{
min = n + 1;
cout << n << " too low\n";
}
else if (n > guess)
{
max = n;
cout << n << " too high\n";
}
if(min == max)
n = min;
if(n == guess)
{
cout << n << " success\n";
break;
}
}
return 0;
}
Or use this function as suggested in comment, to find a number within a range.
int rand_rang(int min, int max)
{
if(min == max)
return min;
return min + (int)((double)rand() / ((double)RAND_MAX + 1) * (max - min));
}
These are all pseudo random numbers. If you are designing this game for a lottery corporation, then use a secure random number generator which is more difficult to crack. If distribution is very important (physics simulation etc.) then again you want to avoid rand

Reading into an Array Multiple Times

I'm having a little trouble with my code. It's pretty much supposed to open two files, and compare the first twenty line of the file "StudentAnswers.txt" [inputted as a char into a char array] against a char value in (each line of another file) "CorrectAnswers.txt" in another array at the same position (index). It's like a linear search, but the same position in the arrays. Then a report should be displayed, detailing which question the student missed, the given answer, the correct answer, and if the student passed (got >= 70%) or not, like the following:
Report for Student X:
2 (A/D), 3 (C/D), 5(D/A)
This student passed the exam!
Then it should clear the SAArray, and feed the next twenty lines from StudentAnswers.txt, and start the process all over again. I guess the program has to determine the number of students from (lines of 'StudentAnswers.txt' file / 20).
I'm having trouble displaying the report, and having the array clear itself after the program. I'm guessing this can be done with a while loop and an accumulator for the number of students (to be determined by above equation).
Also, Visual Studio seems to go to "Missed __ questions for a total of ___ %", and then keep looping -858993460.
Any help would be appreciated.
#include <iostream>
#include <fstream>
#include <string>
#include <array>
#include <algorithm>
using namespace std;
void GradeReturn(char[], char[], int, int, int);
string PassFail(float);
int main()
{
ifstream SA("StudentAnswers.txt");
ifstream CA("CorrectAnswers.txt");char CAArray[20];
char SAArray[20];
// char SA2Array[20];
bool isCorrect;
int correct;
int incorrect;
int counter;
correct = 0;incorrect = 0;
counter = 0;
cout << endl;
if (!SA.fail())
{
cout << "'StudentAnswers.txt' file opened successfully." << endl;
cout << "'CorrectAnswers.txt' file opened successfully." << endl << endl;
int a = 0;
int b = 0;
while (a < 20)
{
CA >> CAArray[a];
a++;
} // while loop to feed char into the array
while (b < 20)
{
SA >> SAArray[b];
b++;
}
} // while loop to feed char into array
CA.close(); // closing "CorrectAnswers.txt"
SA.close(); // closing "StudentAnswers.txt"
GradeReturn(&CAArray[counter], &SAArray[counter], correct, incorrect, counter);
return 0;
}
void GradeReturn(char CAArray[], char SAArray[], int correct, int incorrect, int counter)
{
float percent;
float hundred;
int student;
int catcher[20];
int writeCatcher; int starter;
int catcher_size;
student = 0;
writeCatcher = 0;
catcher_size = ((sizeof catcher) / 4);
while (counter < 20)
{
if ((CAArray[counter]) == (SAArray[counter]))
{
correct++;
cout << "Good job!" << endl;
} // correct handling
else
{
incorrect++;
cout << "You got question " << counter << " wrong." << endl;
counter >> catcher[writeCatcher];
writeCatcher++;
} // incorrect handling
counter++;
} // while loop to determine if a student got a question right or wrong
static_cast <float> (incorrect); // float conversion
cout << endl; // for cleanliness
percent = ((static_cast <float> (correct)) / 20); // percentage
hundred = percent * 100;
PassFail(percent);
if (PassFail(percent) == "pass")
{
student++;
cout << "Report for Student " << student << ":" << endl;
cout << "-----------------------------" << endl;
cout << "Missed " << incorrect << " questions out of 20 for ";
cout << hundred << " % correct." << endl << endl;
starter = 0;
while (starter < (sizeof catcher)
{
if(1=1)
{
catcher_size
}
else
{
cout << "";
starter++;
}
}
}
else if (PassFail(percent) == "fail")
{
student++;
cout << "Missed " << incorrect << " questions out of 20 for ";
cout << hundred << " % correct." << endl << endl;
while (starter < catcher_size)
{
if ((catcher[starter]) == -858993460)
{
starter++;
}
else
{
cout << "";
starter++;
}
}
}
return;
}
string PassFail(float percent)
{
if (percent >= 0.70) // if <pass>
{
return "pass";
}
else // if <fail>
{
return "fail";
}
cout << endl;
}
To get a loop you should keep streams open instead of closing them after reading 20 lines.
As pseudo code that would be:
a = 0;
while(streams_not_empty)
{
CA >> CAArray[a];
SA >> SAArray[a];
++a;
if (a == 20)
{
GradeReturn(&CAArray[counter], &SAArray[counter], correct, incorrect, counter);
a = 0; // Reset a
}
}
CA.close(); // closing "CorrectAnswers.txt"
SA.close(); // closing "StudentAnswers.txt"
You would also need to pass correct, incorrect, counter by reference so that the GradeReturn can change their value and their by do the accumulation.
Like:
void GradeReturn(char CAArray[], char SAArray[], int& correct, int& incorrect, int& counter)
Further you shouldn't rely on being able to read exactly Nx20 lines from the files every time. A file could have, e.g. 108 (5x20 + 8) lines, so you code should be able to handle the with only 8 lines. In other words, don't hard code 20 in your function like while (counter < 20). Instead pass the number of lines to be handled and do while (counter < number_to_handle).
Something like this as pseudo code:
a = 0;
while(streams_not_empty)
{
CA >> CAArray[a];
SA >> SAArray[a];
++a;
if (a == 20)
{
GradeReturn(&CAArray[counter], &SAArray[counter], correct, incorrect, counter, a);
// ^
a = 0; // Reset a
}
}
if (a != 0)
{
// Process the rest
GradeReturn(&CAArray[counter], &SAArray[counter], correct, incorrect, counter, a);
}
CA.close(); // closing "CorrectAnswers.txt"
SA.close(); // closing "StudentAnswers.txt"
One problem you have is you're trying to compare C-style strings with the == operator. This will compare them essentially as if they were pointers to char, i.e. compare whether they point at the same location in memory, not compare the contents of the string. I urge you to look up array-decay and c-string variables to understand more.
Specifically, if (PassFail(percent) == "pass") isn't going to do what you want it to. strcomp doc, strncmp doc using std::string variables instead of c-style strings would all work, but it would be better simply to compare percent to a value, i.e. if(percent >= 0.70 directly instead of calling PassFail and comparing a string.
There are many other issues here also, you at one point call PassFail but do nothing with the return value. The only side affect of PassFail is cout << endl, if that's what you intend, it's a poor decision and hard to read way to put a newline on the console.
Try asking your compiler for more warnings, that's often helpful in finding these types of issues. -Wall -Wextra work for gcc, you may have to read your compiler manual...

Recursively return if statement calls

I'm trying to design a program that takes an integer array as input, and then returns all combinations of values that add up to a predetermined sum. For the sake of clarity, my recursive function will return true when the total adds up to 10.
However, I also want it to return the values from the array that comprise of this total, so my definition is as follows;
If suminarray returns true, print each number from the array.
My hope was, once my base clause is reached, the recursion would unwind, and my if statements would all be evaluated, and each value would be printed from my if statement. However, all that is printed is last value from the array which made up the target total, not all the values that preceded it.
I've likely misunderstood the recursive behaviour of C++. I know how to work with recursive return calls, but logically, if the if statement can't be evaluated until the recursive function returns true or false, shouldn't they unwind, also?
#include <iostream>
bool suminarray(int *numbers, const int &size, int startPos, int total);
using namespace std;
int main()
{
int numbers[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
int startPos = 0;
int total = 0;
suminarray(numbers, 10, 0, total);
return 0;
}
bool suminarray(int *numbers, const int &size, int startPos, int total)
{
if(total == 10)
{
cout << "result. " << endl;
return true;
}
else if(total > 10)
{
return false;
}
else
{
for(int i = startPos; i < size; i++)
{
cout << " loop " << i << endl;
cout << " total" << total << endl;
if(suminarray(numbers, size, i+1, total+numbers[i]) == true)
{
cout << "Uses " << numbers[i] << endl;
}
}
}
}
Edit: correction to source code.
The immediate problem (which your compiler should be warning you about), is that you have no return statement in the final else block, which causes the function to fall off the end without returning either true or false, leading to undefined behavior. If you fix that in the most obvious way:
else
{
for(int i = startPos; i < size; i++)
{
cout << " loop " << i << endl;
cout << " total" << total << endl;
if(suminarray(numbers, size, i, total+numbers[i]) == true)
{
cout << "Uses " << numbers[i] << endl;
return true;
}
}
return false;
}
your program then works, but it only prints the FIRST set of values that add up to 10 that it finds.
That immediately shows you the problem with your approach -- each function call can only return ONCE -- you can't (easily) have it both return success AND continue to try more alternatives.
As you've already guessed, the way you're imagining the recursive function unwinding is wrong.
In your example, you want to get to a total of 10, with numbers starting at 1, and ending at 9. So, first your recursive function will make the total = 1. Then it will add another 1 to that until it gets all the way down to the tenth 1. Then it will print result, then it will unwind 1 step, and print 1.
Good so far right? Well, here's where it goes off track. At this point it doesn't unwind all the way. It still stays at 9, but this time it adds a 2 to that, fails goes back until it unwinds to a sum of 8. Now it tries 2 and works this time! Printing result, then 2.
This, as i've understood, isn't what you want. What you should be doing is make something else to hold your array of answers, and not just print them.
I know how to work with recursive return calls, but logically, if the if statement can't be evaluated until the recursive function returns true or false, shouldn't they unwind, also?
This is correct. The reason you are only seeing one print statement at the end is because only one call is returning 'true'. Therefore the 'if' statement is only true once and you only see one print statement for "Uses ".
I believe your mistake is that you didn't add a return statement after your for loop. This means the return value for your function is actually undefined. Start using the -Wall flag when you compile to make sure you don't make this mistake. Here is a version where I added a "return true;" after the 'for' loop:
#include <iostream>
bool suminarray(int *numbers, const int &size, int startPos, int total);
using namespace std;
int main()
{
int numbers[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
int startPos = 0;
int total = 0;
suminarray(numbers, 10, startPos, total);
return 0;
}
bool suminarray(int *numbers, const int &size, int startPos, int total)
{
if(total == 10)
{
cout << "result. " << endl;
return true;
}
else if(total > 10)
{
return false;
}
else
{
for(int i = startPos; i < size; i++)
{
cout << " loop " << i << endl;
cout << " total" << total << endl;
if(suminarray(numbers, size, i, total+numbers[i]) == true)
{
cout << "Uses " << numbers[i] << endl;
}
}
}
return true;
}

Using an iterator in a recursive function results in a segmentation fault

I wrote a program that takes in N test cases of integers representing skill levels of students and attempts to find the total number of the smallest group possible if the only restriction is that there can be no to skill levels that are equal on a team and there is no skill gap greater than 1. So the following test case:
4 5 2 3 -4 -3 -5
would output:
3
Because the teams possible are {-4,-3,-5} and {4,5,2,3}, since the first group is only three members the output is 3.
I decided to use a linked list and a recursive function to solve the problem. One recursive function would go left and right of an integer looking for an integer that was higher by one size, is one is found then the element is removed from the list and 1 is returned. The same is done with another function looking for an integer smaller by 1. This should result in the sum of a group and I could compare the different sums to find the smallest. Unfortunately when I tried to implement this not only do I get a segmentation fault but the number that comes out after a few iterations are not even a part of the list and really large.
#include <cmath>
#include <cstdio>
#include <list>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int findHigherSkillLevel(int skillLevel, list<int>::iterator *it, list<int> &list) {
if (it == NULL) return 0;
if (**it == (skillLevel + 1)) {
//cout << "test3" << endl;
skillLevel++;
list.erase(*it);
*it = list.begin();
//cout << "Iterator in the higher skill level function if it finds a skill level higher by 1: " << **it << endl;
//cout << "The skill level is: " << skillLevel << endl;
return 1 + findHigherSkillLevel(skillLevel, it, list);
} else {
//cout << "Iterator in the higher skill level function if it doesn't find one: " << **it << endl;
return findHigherSkillLevel(skillLevel, ++it, list);
}
return 0;
}
int findLowerSkillLevel(int skillLevel, list<int>::iterator *it, list<int> &list) {
if (it == NULL) return 0;
if (**it == (skillLevel - 1)) {
skillLevel--;
list.erase(*it);
*it = list.begin();
return 1 + findLowerSkillLevel(skillLevel, ++it, list);
} else {
//cout << "test2" << endl;
return findLowerSkillLevel(skillLevel, ++it, list);
}
return 0;
}
int findGroupsSizes(list<int>::iterator *it, list<int> &list) {
if (it == NULL) return 0;
int groupSize = 1;
int skillLevel = **it;
*it = list.erase(*it);
//cout << "Iterator value in the first function: " << **it << endl;
groupSize += findHigherSkillLevel(skillLevel, it, list) + findLowerSkillLevel(skillLevel, it, list);
return groupSize;
}
If I were to use the test case mentioned then it would iterate through 4, then 5, then 2, and then some weird numbers pop out and finally a seg fault. Is it impossible to use iterators on recursive functions if you pop them from the list in those recursions?
main() actually takes in t total test cases followed by t lines of N separated integers. I used the following as a test case:
4
7 4 5 2 3 -4 -3 -5
1 -4
4 3 2 3 1
7 1 -2 -3 -4 2 0 -1
Here is main if it matters:
int main() {
int t; // the number of test cases
cin >> t;
vector<list<int> > skillLevels(t, list<int>());
// input for each test case
for (int i = 0; i < t; i++) {
int n; // number of students for this test case
cin >> n;
// initialize the list for this test case
for (int j = 0; j < n; j++) {
int skillLevel;
cin >> skillLevel;
skillLevels[i].push_back(skillLevel);
}
}
// recursively scan lists for smallest teams
for (int i = 0; i < t; i++) {
int minGroupNumber = skillLevels[i].size();
list<int>::iterator iterator = skillLevels[i].begin();
int skillLevel = skillLevels[i].front();
while (!skillLevels[i].empty()) {
iterator = skillLevels[i].begin();
int currentGroupSize = findGroupsSizes(&iterator, skillLevels[i]);
cout << currentGroupSize << endl;
if (currentGroupSize < minGroupNumber)
minGroupNumber = currentGroupSize;
//cout << minGroupNumber << endl;
if (!skillLevels[i].empty()) skillLevels[i].pop_front();
}
cout << minGroupNumber << endl;
}
return 0;
}
++it is incrementing the pointer (which makes it invalid) not the iterator. You probably want ++*it.
But that might also take you beyond the end of the list.