Generating Distinct Random Numbers in C++ - c++

For part of a programming assignment I need to generate multiple sets of 10 numbers with a range of 1 to 50 with no repeats in each individual set, so I created the following code:
int Numbers[10]; //array to store the random numbers in
bool Duplicate; //variable to check or number is already used
srand(time(NULL)); //seeding the random number generator
// do while loop used to allow user to generate multiple sets
do {
Duplicate = false; // set check to false
//for loop to generate a complete set of 10 random numbers
for (int I = 0; I < 10; I++)
{
// do while loop used to generate random numbers until a distinct random number is generated
do
{
Numbers[I] = (rand()%50) + 1; // generates a random number 1 - 50 and stores it into Numbers[I]
// for loop used to check the other numbers in set for any repeats
for (int J = I - 1; J > -1; J--) // works backwards from the recently generated element to element 0
if (Numbers[I] == Numbers[J]) //checks if number is already used
Duplicate = true; //sets Duplicate to true to indicate there is a repeat
} while (Duplicate); //loops until a new, distinct number is generated
}
//at this point in the program we should have an array Numbers[] with a set of 10 unique random numbers 1 - 50
// loop to print numbers to the screen
for (int I = 0; I < 10; I++)
cout << Numbers[I] << " "; // printing the element to the screen
cout << endl;
cout << "Do you want to run the program again (Y/N): "; // Asks user if they want to create another set of 10 numbers
char Answer; // used to store users answer
cin >> Answer; // stores users answer
} while (Answer == 'Y' || Answer == 'y'); // loop program if the user wants to generate another set
However, I seem to be having trouble with the do while loop that generates random numbers until a new, distinct number is generated.
After some testing and tinkering, I found that I have somehow created an infinite loop there and cannot figure out the problem.
Some ideas that I think may be causing the problem:
-How does the rand function change the seed and is the seed being changed to create a new pseudorandom number?
-Is my for loop to check for repeats outstepping the bounds of the array?
Any advice and hints would be greatly appreciated.

You're forgetting to reset Duplicate back to false. First time it is set to true it remains true, enabling an infinite do...while loop.

Start with an ordered array of 1 to 50, then shuffle it via a Fisher-Yates shuffle. Then just take the first 10 numbers.

Notice that you don't reinitialize Duplicate to false in the beginning of your do-while loop meaning that after you have one duplicate random number - Duplicate is set to true and remains true forever therefore - your do-while loop will run forever.

Related

Infinite Loop where if statements aren't being called

I'm trying to write a piece of code that goes through a random element of a string array and then outputs it. After it outputs it then sets that element to 0. And then that if statement ensures that name will not be outputted again.
void group(){
int random = rand() % 50;
int i, j = 0;
while(j<50){
srand(0);
random = rand() % 50;
groupNum = 1;
cout << "Group " << groupNum << " has: ";
if(names[random] != "0"){
cout << names[random] << " ";
names[random] = "0";
j++;
}
if(names[random] == "0"){
continue;
}
i++;
if(i == peoplePerGroup){
groupNum++;
cout << "\n\n";
i=0;
}
}
}
srand function (as a pseudo-random number generator) should only be seeded once, before any calls to rand(), and the start of the program. It should not be repeatedly seeded, or reseeded every time you wish to generate a new batch of pseudo-random numbers.
"In order to generate random-like numbers, srand is usually initialized to some distinctive runtime value, like the value returned by function time (declared in header ). This is distinctive enough for most trivial randomization needs."
Also, every time your function runs, it's get a random element of your array and sets it to zero. The only way this loop ends is in a scenario that every single elements on this array were setted to zero. Buy in each loop, the index choosed is random. Think about how many times they need to run until they fill your requirements.
As a little explanation to why the re-seeding with the same number causes this issue:
rand() uses pseudo-randomness and therefore it is reproducable. Basically it meshes up some internal number that is set based on the seed. The number for example has bitwise XOR ( ^ ) applied to a constant etc. After every call, the number is also incremented internally.
Naturally that means that with the same starting number (aka the seed) you get the same results every time.
By the way, your whole code becomes much smoother if you fill all your words into an std::set and remove the word from the set when taking it, instead of setting it to null. See here: How to select a random element in std::set?
Or even easier, fill them into a vector and apply: std::random_shuffle
Then just iterate through that vector a single time to receive the words in random order.

getting infinte amount of inputs from the user than printing the biggest 3 , without using arrays

First time around, first time learning to code anything. Sorry for my ignorance.
So I've been asked to code a program that gets infinite amount of number from the users until he submits the number I manage to do so very well, but I also need to print the biggest sum of a following three inputs, for example, the user inputs 4,20,2,4,11,9,8,1 the program should print 11,9,8 because the sum of those 3 is greater than all other 3.
I must tell you I cannot use arrays, I know its a bummber but I know it is possible to do so without.
I was trying to build a function that tries to act like an array but I can't really call her back since its a two-variable function and one of them is the input, which I obviously don't know. was working on this question for 5 hours now and thought ill ask for your wisdom
cout << " enter numbers as long as you wish" << endl;
cout << "when you wish to stop enter the number 1" << endl;
int n;
int sum;
int i = 1;
while (n != 1) {
cin >> n;
remember(i, n);
if (n == 1) {
cout << "you choosed to stop " << endl;
break;
}
i++;
}
And the function I was trying to build is really simple but I can't call any specific value for example remember(1, n) when I want to sum them up and see who is bigger.
int remember(int i, int n){
return n;
}
*** Please note that the sums that are being tested are the sums of the numbers in the exact order that the user-submitted therefor 11,9,8 is the output and NOT 20,11,9
You need seven variables: Three which is the "window" you're currently reading, and which you check your sum with; Three which is the "biggest sum" triple; And one which is the current input.
For each input you read into the "current input" variable, you shift the window down one value and set the top variable to the just read input.
Then you take the sum of all three values in the window, and check if it's bigger than the sum of the current "biggest sum" triple. If it is, then you make the "biggest sum" triple equal to the current window values.
Iterate until there is no more input, and then print the "biggest" values.
Regarding the shifting of the three window values, lets say you have three variables named window1, window2 and window3 then you could shift like this:
window1 = window2;
window2 = window3;
window3 = current;
Checking the sum is as easy as
if ((window1 + window2 + window3) > (biggest1 + biggest2 + biggest3))
All window and biggest variables need to be initialized to the lowest possibly value for the type (for int that would be std::numeric_limits<int>::min()).
Since you initialize all values, there's no need to have special cases for the first and second input.
Iterating while there's input could be done by doing
while (std::cin >> current)
First of all, n is uninitialized, so it's undefined behavior when you do while (n != 1){. So technically, there's no guarantee that anything works past that. You should initialize it, for example by setting it to 0 (or any other value that's not 1, in this case):
int n = 0;
But the issue that you observe is because you have another int n; in your loop, which shadows the outer n (the one that is checked in the while condition). So the cin >> n; only ever modifies that inner n. The outer one will stay at the same uninitialized value. So if that value made it enter the loop, it will never exit the loop, because n != 1 is always true.
Remove the int n; inside the loop to solve the problem.
Basically, what you need is 4 variables to account the actual list and its sums (3 for the list and 1 for the sum of it)
You need 3 more variables to account the actual list.
At each interaction, you have two things to do:
Compare the sum of actual list with the stored one. If the sum the actual list is greater than that stored, actualize it
For each new number, rotate you variables that account for the actual list.
In pseudo code:
v3 = v2;
v2 = v1;
v1 = new_number;

Prime Factorization of First 1000 Numbers in C++

I need to write a program that could find the sums of the prime factors of the first 1000 numbers, check if the sums are prime, and print them if they are.
I have some pseudo-code I've written and I have a working program for generating prime numbers that I'm trying to expand off of. I'm learning from the book "Jumping into C++," by the way (it's a Practice Problem in the book).
This is the pseudo-code:
// for every 1000 of the first bunch of numbers, check if the number is prime
// if (number isPrime())
// use expression <number_being_checked % number_being_compared_against == 0;>
// if (number_being_checked % number_being_compared_against == 0)
// for every number found from dividing the two numbers, check if number is prime
// add up prime numbers and check if the sums are prime
// else, return false in bool function isFactorPrime() (if I write such a function)
And this is the main() function right now:
int main ()
{
for (int i = 0; i < 1000; i++)
{
if (isFactorPrime(i))
{
cout << i
}
}
}
The issue I'm having right now is about what I should add to i (i + some_variable?) to get my sum that I can use in my check to see if it's a prime number. Should I make an inner for-loop and then add loop-variable in that to i, with expression i + j? Where I'd assign j the value of the number being checked (which is what I'm wondering how I could do. It's not like I'm going to take the user's input, I'm just iterating over the first 1000 numbers and checking them).
There are also some other Practice Problems in the book I need to ask help with, but for now I'll go with just this one.

Understanding Sum of subsets

I've just started learning Backtracking algorithms at college. Somehow I've managed to make a program for the Subset-Sum problem. Works fine but then i discovered that my program doesn't give out all the possible combinations.
For example : There might be a hundred combinations to a target sum but my program gives only 30.
Here is the code. It would be a great help if anyone could point out what my mistake is.
int tot=0;//tot is the total sum of all the numbers in the set.
int prob[500], d, s[100], top = -1, n; // n = number of elements in the set. prob[i] is the array with the set.
void subset()
{
int i=0,sum=0; //sum - being updated at every iteration and check if it matches 'd'
while(i<n)
{
if((sum+prob[i] <= d)&&(prob[i] <= d))
{
s[++top] = i;
sum+=prob[i];
}
if(sum == d) // d is the target sum
{
show(); // this function just displays the integer array 's'
top = -1; // top points to the recent number added to the int array 's'
i = s[top+1];
sum = 0;
}
i++;
while(i == n && top!=-1)
{
sum-=prob[s[top]];
i = s[top--]+1;
}
}
}
int main()
{
cout<<"Enter number of elements : ";cin>>n;
cout<<"Enter required sum : ";cin>>d;
cout<<"Enter SET :\n";
for(int i=0;i<n;i++)
{
cin>>prob[i];
tot+=prob[i];
}
if(d <= tot)
{
subset();
}
return 0;
}
When I run the program :
Enter number of elements : 7
Enter the required sum : 12
Enter SET :
4 3 2 6 8 12 21
SOLUTION 1 : 4, 2, 6
SOLUTION 2 : 12
Although 4, 8 is also a solution, my program doesnt show it.
Its even worse with the number of inputs as 100 or more. There will be atleast 10000 combinations, but my program shows 100.
The Logic which I am trying to follow :
Take in the elements of the main SET into a subset as long as the
sum of the subset remains less than or equal to the target sum.
If the addition of a particular number to the subset sum makes it
larger than the target, it doesnt take it.
Once it reaches the end
of the set, and answer has not been found, it removes the most
recently taken number from the set and starts looking at the numbers
in the position after the position of the recent number removed.
(since what i store in the array 's' is the positions of the
selected numbers from the main SET).
The solutions you are going to find depend on the order of the entries in the set due to your "as long as" clause in step 1.
If you take entries as long as they don't get you over the target, once you've taken e.g. '4' and '2', '8' will take you over the target, so as long as '2' is in your set before '8', you'll never get a subset with '4' and '8'.
You should either add a possibility to skip adding an entry (or add it to one subset but not to another) or change the order of your set and re-examine it.
It may be that a stack-free solution is possible, but the usual (and generally easiest!) way to implement backtracking algorithms is through recursion, e.g.:
int i = 0, n; // i needs to be visible to show()
int s[100];
// Considering only the subset of prob[] values whose indexes are >= start,
// print all subsets that sum to total.
void new_subsets(int start, int total) {
if (total == 0) show(); // total == 0 means we already have a solution
// Look for the next number that could fit
while (start < n && prob[start] > total) {
++start;
}
if (start < n) {
// We found a number, prob[start], that can be added without overflow.
// Try including it by solving the subproblem that results.
s[i++] = start;
new_subsets(start + 1, total - prob[start]);
i--;
// Now try excluding it by solving the subproblem that results.
new_subsets(start + 1, total);
}
}
You would then call this from main() with new_subsets(0, d);. Recursion can be tricky to understand at first, but it's important to get your head around it -- try easier problems (e.g. generating Fibonacci numbers recursively) if the above doesn't make any sense.
Working instead with the solution you have given, one problem I can see is that as soon as you find a solution, you wipe it out and start looking for a new solution from the number to the right of the first number that was included in this solution (top = -1; i = s[top+1]; implies i = s[0], and there is a subsequent i++;). This will miss solutions that begin with the same first number. You should just do if (sum == d) { show(); } instead, to make sure you get them all.
I initially found your inner while loop pretty confusing, but I think it's actually doing the right thing: once i hits the end of the array, it will delete the last number added to the partial solution, and if this number was the last number in the array, it will loop again to delete the second-to-last number from the partial solution. It can never loop more than twice because numbers included in a partial solution are all at distinct positions.
I haven't analysed the algorithm in detail, but what struck me is that your algorithm doesn't account for the possibility that, after having one solution that starts with number X, there could be multiple solutions starting with that number.
A first improvement would be to avoid resetting your stack s and the running sum after you printed the solution.

Random number always generates 1 number

//Generate Food Personality
for(i=0; i<food.size(); i++)
{
srand(time(0));
int randomFood = rand() % 6;
if(randomFood == 1 || randomFood == 3 || randomFood == 5)
{
badFood.push_back(food[randomFood]);
}
else if(randomFood == 0 || randomFood == 2 || randomFood == 4)
{
goodFood.push_back(food[randomFood]);
}
}
cout << "Size of Food Vector: " << food.size() << endl;
cout << "Size of Bad Food: " << badFood.size() << endl;
cout << "Size of Good Food " << goodFood.size() << endl;
randomFood is a random number through 6 and it takes the random number in food[] and adds it to
a vector depending on how the random number turns out.
My problem is it seems that its always generating an odd or even number. and the bad and good.size() always prints out as 6 or 0, never anything else.
Calling srand(time(0)); at the beginning of the loop is resetting the random number generator every time through the loop. Thus, you will keep getting the same initial random number every time.
(Technically it would be possible for time(0) to return a different value between iterations of the for loop, but given the speed of today's processors it would be a very rare case when this happens for the code you have provided.)
In any case, you should call srand right before the for loop (or, better yet, just once at the beginning of your program's main routine.)
put the srand() outside of your for loop. You are always reinitializing your random seed.
The problem is that you're seeding your random number generator at the beginning of each loop. Since the loop runs so quickly, it's seeding the same time value every iteration, thus producing the same random number when you call rand.
Also, don't use use the modulo operator with random number generators; that uses the least significant bits (which are almost deterministic) rather than the leading bits (which are closer to being pseudorandom). Divide by six and truncate to an integer instead.
Finally, I'd recommend replacing the superfluous
else if(randomFood == 0 || randomFood == 2 || randomFood == 4)
with
else
Move the srand() outside of the loop.
Your loop is probably taking less than a second each time around, so time(0) is always returning the same value (its resolution is one second), so srand(time(0)) is always seeding the random number generator with the same seed, so rand() is always using the same sequence, so you get the same random number each time around the loop.
You need to move your call to srand above the for loop. This loop is executing very quickly (most likely) so time is returning the same value each time, so you are reseeding your random number generator with the same value, which will generate the same list of psudo-random numbers. You are only using the first member of the same list over and over, until the computer's clock clicks into the next second.
Call srand(time(0)) only once per thread. It shouldn't be called multiple times like in your loop.
I think it's because you are re-seeding the random number generator for each loop iteration. Move srand(time(0)); out side of the for loop