c++ vector with random unique elements with constant sum - c++

I have an std::vector with fixed size N = 5. I want every element of the vector to be randomly selected between two positive numbers, in particular 1 and 12. (zeros are not allowed).Each element should be unique on the vector.
How can I do this? The implementation so far allows elements to be zero and have duplicates in the vector. I want to improve in order not to allow zeros and duplicates
Code so far:
#include <algorithm>
#include <array>
#include <iostream>
#include <iterator>
#include <random>
int main() {
std::random_device rd;
std::mt19937 gen(rd());
constexpr int MAX = 20;
constexpr int LINES = 5;
int sum{};
int maxNum = 12;
int minNum = 1;
std::array<int, LINES> nums;
for (int i = 0; i < LINES; ++i) {
maxNum = std::min(maxNum, MAX - sum);
minNum = std::min(maxNum, std::max(minNum, MAX - maxNum * (LINES - i)));
std::cout << minNum << " " << maxNum << std::endl;
std::uniform_int_distribution<> dist(minNum, maxNum);
int num = dist(gen);
nums[i] = num;
sum += num;
}
std::shuffle(std::begin(nums), std::end(nums), gen);
std::copy(std::begin(nums), std::end(nums), std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
}

Ok, there are three requirements:
Sum should be fixed
Non-repetitive numbers
Numbers should be in the range
For requirement #1 it is better sample from distribution which already have the property - Dirichlet distribution. For simplest case where all parameters are equal to 1, it is also known as simplex sampling, producing numbers uniformly distributed on N dimensional simplex. HEre is link to the C++ code.
To satisfy second&third requirement, just use acceptance/rejection
std::linear_congruential_engine<uint64_t, 2806196910506780709ULL, 1ULL, (1ULL<<63ULL)> ugen;
float MAX = 20.0f;
Simplex s(0.0f, 20.0f);
std::vector<float> v(5, 0.0f);
std::vector<int> r(5, 0);
for( ;; ) {
s.sample(v, ugen); // sampled Dirichlet
for(int k = 0; k != v.size(); ++k) {
r[k] = 1 + int(v[k]);
}
std::sort(r.begin(), r.end());
if (*r.rbegin() > 12) // array is sorted, just check last largest element
continue;
if (std::unique(r.begin(), r.end()) == r.end()) // no duplicates, good to go
break;
}
return r;

declare a boolean that starts at false, after that do a while that whill iterate until that flag is true, inside that while you will iterate until the sum of both of them = 5, you will check if the sum = 5 with an If statement, if they are then you will change the value of the flag to true. Easy as that.
I recommend you study a bit more, since you are probably new to programming (at least thats what the question makes me think, if you aren't then there is something clearly wrong).
Also, there ya go:
If statements
While loop

Related

Minimum number of steps to equalize distinct character of the string [duplicate]

This question already has answers here:
How to find the minimum number of operation(s) to make the string balanced?
(5 answers)
Closed 1 year ago.
I'm trying to write this program that asks for user input of string, my job is to print out the minimum number of steps required to equalize the frequency of distinct characters of the string.
Example
Input
6
aba
abba
abbc
abbbc
codedigger
codealittle
Output
1
0
1
2
2
3
Here is my program:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <unordered_map>
using namespace std;
int main()
{
unordered_map<char, int >m;
vector<int> vec1, vec2;
string s;
int n;
cin >> n;
cin.ignore();
for (int i = 0; i < n; ++i)
{
m.clear();
vec1.clear();
getline(cin, s);
for (int i = 0; i < s.size(); i++)
m[s[i]]++;
for (auto itr : m)
vec1.push_back(itr.second);
sort(vec1.begin(), vec1.end());
int mid = vec1[vec1.size() / 2];
int ans = 0;
for (auto itr : vec1)
ans += abs(mid - itr);
vec2.push_back(ans);
}
for (int i = 0; i < vec2.size(); ++i)
cout << vec2[i] << endl;
}
What I tried to do is for each test case:
Using an unordered_map to count the frequency of the characters of the string.
Push the key values of the map to a vector.
Sort the vector in ascending order.
Calculate the middle element of the vector to equalize the distinct characters with as least steps as possible.
The result will add the difference between the middle element with the current element.
Push the result to another vector and print it.
But my result is wrong at test case number 5:
1
0
1
2
3 // The actual result is 2
3
I don't understand why I get the wrong result, can anyone help me with this? Thanks for your help!
The issue is that your algorithm is not finding the optimal number of steps.
Consider the string you obtained an incorrect answer for: codedigger. It has 4 letters of frequency 1 (coir) and 3 letters of frequency 2 (ddeegg).
The optimal way is not to convert half the letters of frequency 2 into some new character (not present in the string) to make all frequency 1. From my understanding, your implementation is counting the number of steps that this would require.
Instead, consider this:
c[o]dedigge[r]
If I replace o with c and r with i, I obtain:
ccdediggei
which already has equalized character frequencies. You will note that I only performed 2 edits.
So without giving you a solution, I believe this might still answer your question? Perhaps with this in mind, you can come up with a different algorithm that is able to find the optimal number of edits.
Your code correctly measures the frequencies of each letter, as the important information.
But then, there were mainly two issues:
The main target value (final equalized frequency) is not necessarily equal to the median value. In particular, this value must divide the total number of letters
For a given targeted height value, your calculation of the number of steps is not correct. You must pay attention not to count twice the same mutation. Moreover, the general formula is different, depending the final number of different letters is equal, less or higher than the original number of letters.
The following code focuses on correctness, not on efficiency too much. It considers all the possible values of the targeted height (frequency), i.e. all the divisors of the total number of letters.
If efficiency is really a concern (not mentioned in the post), then for example one could consider that the best value is unlikely to be very far from the initial average frequency value.
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <numeric>
#include <unordered_map>
// calculates the number of steps for a given target
// This code assumes that the frequencies are sorted in descending order.
int n_steps (std::vector<int>& freq, int target, int nchar) {
int sum = 0;
int n = freq.size();
int m = nchar/target; // new number of characters
int imax = std::min (n, m);
for (int i = 0; i < imax; ++i) {
sum += std::abs (freq[i] - target);
}
for (int i = imax; i < n; ++i) {
sum += freq[i];
}
if (m > n) sum += m-n;
sum /= 2;
return sum;
}
int main() {
std::unordered_map<char, int >m;
std::vector<int> vec1, vec2;
std::string s;
int n;
std::cin >> n;
std::cin.ignore();
for (int i = 0; i < n; ++i)
{
m.clear();
vec1.clear();
//getline(cin, s);
std::cin >> s;
for (int i = 0; i < s.size(); i++)
m[s[i]]++;
for (auto itr : m)
vec1.push_back(itr.second);
sort(vec1.begin(), vec1.end(), std::greater<int>());
int nchar = s.size();
int n_min_oper = nchar+1;
for (int target = 1; target <= nchar; ++target) {
if (nchar % target) continue;
int n_oper = n_steps (vec1, target, nchar);
if (n_oper < n_min_oper) n_min_oper = n_oper;
}
vec2.push_back(n_min_oper);
}
for (int i = 0; i < vec2.size(); ++i)
std::cout << vec2[i] << std::endl;
}

Generate Random 20 Non-repeating numbers in C++

So I have a program where I generate a 8x8 matrix which are rooms. So we have 64 rooms. Now I have to generate 20 random rooms to be dirty. I'm trying to figure out how I can generate 20 non repeating numbers to use as the dirty rooms. This is my code so far:
//generate the 20 random dirty rooms
int col;
int row;
for (int i = 0; i < 20; i++)
{
col = ranNumber();
row = ranNumber();
cout << "\t" << col << " " << row << endl;
if (room[row][col] == 'D')
{
cout << "Duplicate" << endl;
col = ranNumber();
row = ranNumber();
cout << "New number " << row << col << endl;
room[row][col] = 'D';
}
else
//set the room as dirty
room[row][col] = 'D';
}
*ranNumber():
int ranNumber() {
return rand() % 8;
}
Since you're not dealing with a particularly large data set, I'd suggest using std::shuffle. You'll want to initialize your rooms with 20 dirty (the positions don't matter, so do whatever is easiest), then let std::shuffle rearrange the rooms. This avoids you having to write your own loop in case you get poor luck with your random generator, and better expresses your intent.
Sample code:
int main() {
char rooms[8][8];
for(auto i = 0; i < 8; ++i) {
for(auto j = 0; j < 8; ++j) {
rooms[i][j] = (i == 0) ? 'D' : ' ';
}
}
printRooms(rooms);
std::random_device rd{};
std::default_random_engine re{rd()};
auto b = (char *) rooms;
std::shuffle(b, b + (8 * 8), re);
std::cout << "----------------------\n";
printRooms(rooms);
return 0;
}
You can create an array of room numbers (0-63) and use as a picking basket. Whenever a room has been picked, you swap that room out of the selectable range.
Example:
#include <algorithm> // fill_n
#include <iostream>
#include <numeric> // iota
#include <random> // mt19937, random_device, uniform_int_distribution
int main() {
std::mt19937 prng(std::random_device{}());
char room[8][8];
constexpr int room_count = 8 * 8;
std::fill_n(&room[0][0], room_count, '.'); // fill rooms with an initial value.
char numbers[room_count];
std::iota(std::begin(numbers), std::end(numbers), 0); // 0 - 63
for(int i = 1; i <= 20; ++i) {
int last_selectable_room = room_count - i;
std::uniform_int_distribution<int> dist(0, last_selectable_room);
auto& selected = numbers[dist(prng)];
*(&room[0][0] + selected) = 'D';
// swap the selected room number with the last selecable room number
// to make sure that the selected room can't be selected again
std::swap(selected, numbers[last_selectable_room]);
}
}
Demo
This is likely going to be 2.3 - 2.4 times faster than the std::shuffle approach if you use g++ or clang++. Benchmark
If selecting the dirty rooms uniformly at random is truly important, you could build a random permutation of the rooms using Knuth's shuffle (be careful, it is easy to blunder!) and picking e.g. the first 20 ones of the result as dirty.
You could do it using std::shuffle() and a single-dimension array, exploiting the fact that an m x n matrix can be represented as an array containing m*n elements
#include <vector>
#include <random>
#include <algorithm>
class random_room_generator {
public:
random_room_generator(const size_t matrixRows, const size_t matrixColumns) :
m_matrixRows(matrixRows),
m_randomRoomList(),
m_nextRoom(0)
{
// Create a list of all the room numbers.
const size_t totalRooms = matrixRows * matrixColumns;
for (size_t i = 0; i < totalRooms; ++i) {
m_randomRoomList.push_back(i);
}
// Shuffle the list.
std::random_device rd;
std::mt19937 g(rd());
std::shuffle(m_randomRoomList.begin(), m_randomRoomList.end(), g);
}
std::pair<size_t, size_t> next() {
// Get the room number:
const size_t roomNumber = m_randomRoomList[m_nextRoom++];
if (m_nextRoom == m_randomRoomList.size()) {
// Loop back round to the start if we get to the end of the shuffled list.
m_nextRoom = 0;
}
// Convert the room number into a row and column using the modulus/division operators:
return std::pair<size_t, size_t>(roomNumber % m_matrixRows, roomNumber / m_matrixRows);
}
private:
size_t m_matrixRows;
std::vector<size_t> m_randomRoomList;
size_t m_nextRoom;
};
Then, in your function, instead of calling ranNumber(), you can use an instance of random_room_generator to save a list of random rooms and then get 20 rooms from that list:
random_room_generator gen(8, 8);
for (int i = 0; i < 20; i++)
{
std::pair<size_t, size_t> roomCoords = gen.next();
const size_t row = roomCoords.first;
const size_t col = roomCoords.second;
cout << "\t" << col << " " << row << endl;
//set the room as dirty
room[row][col] = 'D';
}
You can find a working example here: https://godbolt.org/z/xKLmjm

Inquire about using a random integer as the size of a vector

so I have trouble remembering how to call upon random numbers in C++. I'm not sure how to, so if someone could remind me that would be fantastic. I'm trying to make a vector with a random size filled with random integers. Here is my following code:
#include <cstdlib>
#include <iostream>
#include <vector>
int main()
{
int randSize = rand();
int sum = 0;
int product = 1;
std::vector<int> numbers(randSize);
int output;
for (int i = 0; i < numbers.size(); i++)
{
int randNum = rand();
numbers[i] = randNum;
output = numbers[i]&2;
if (output == 0)
{
sum += numbers[i];
}
else
{
product = product * numbers[i];
}
}
std::cout << "The sum of even numbers is " << sum << "\n";
std::cout << "The product of off numbers is " << product << "\n";
}
As already pointed out in the comments, best forget about rand() and use the facilities provided by the standard library in <random> instead. For example:
std::vector<int> makeRandomBunch(int min, int max, std::size_t min_elements, std::size_t max_elements)
{
std::mt19937 generator(42);
std::uniform_int_distribution<std::size_t> size_distribution(min_elements, max_elements);
std::size_t num_elements = size_distribution(generator);
std::vector<int> data;
data.reserve(num_elements);
std::uniform_int_distribution<int> element_distribution(min, max);
std::generate_n(std::back_inserter(data), num_elements, [&](){ return element_distribution(generator); });
return data;
}
Here, we're using an mt19937 pseudorandom number generator (don't get spooked by the name, it's just named after the algorithm it uses) seeded with the value 42 as our source of randomness. An std::uniform_int_distribution can be used to shape the randomness provided by a random generator into random integers sampled from a given range. We use a uniform_int_distribution to randomly pick a size between elements_min and elements_max for our vector and reserve that amount of space in our vector. We use another uniform_int_distribution which we'll pick our int elements from (ranging between min and max). Finally, we use std::generate_n in combination with a back_inserter to fill our vector with elements and return the vector…
live example here

Finding the second smallest sum of contiguous sub arrays

I am writing a function that takes in a pointer that points to an array that is dynamically allocated, in addition to the length of the array. I am trying to find the second smallest sum of it's contiguous sub arrays.
I have been writing code to calculate the second smallest value in an array, and also a piece of code that calculates the sum of all the contiguous sub arrays. I was hoping that I would be able to "merge" these two pieces together to get what my desired end result, but I am getting stuck. I would really appreciate any help.
Thank you.
#include <iostream>
using namespace std;
int secondSmallestSum(int *numbers,int length)
{
//Below shows the sum of all contiguous sub arrays.
for(i = 0; i<= length; ++i)
{
int sum = 0;
for(int j = i; j <= length; ++j)
{
sum+=*(numbers+j);
}
}
//Below calculates the second smallest element in an array
int smallest, secondsmallest;
if (*numbers < *(numbers+1))
{
smallest = *numbers;
secondsmallest = *(numbers+1) ;
}
else {
smallest = *(numbers+1) ;
secondsmallest = *(numbers) ;
}
for (i = 2; i < length; i++) {
if (*(numbers+i) < smallest)
{
secondsmallest = smallest;
smallest = *(numbers+i);
}
else if (*(numbers+i) < secondsmallest)
{
secondsmallest = *(numbers+i);
}
}
}
You can do something like this (of course you need to add range checking).
#include <iostream>
#include <vector>
#include <algorithm>
int main(int argc, char** argv) {
std::vector<int> v{3, 1, 4, 5, 6, 2};
std::nth_element(v.begin(), v.begin() + 1, v.end());
std::cout << "The second smallest element is " << v[1] << "\n";
}
Note: using nth_element will change the order of the elements in the vector.
Correct me if I understand you wrong,
by looking at "find the second smallest sum of it's contiguous sub arrays" and the code you posted, I'm assuming your logic is
calculate all sums of all possible contiguous sub arrays
find the second smallest value in the sums
Actually there is a well known algorithm, Kadane's algorithm, that serves a similar purpose (only Kadane's finds THE smallest, not second smallest). You may want to Google it to find more.
Back to your question, I believe the following code does what you want. The code is a variant of Kadane's algorithm.
#include <climits> // for INT_MAX
int findSecondMinOfContiguousSubarray(int arr[], int n)
{
// to store the minimum value that is ending
// up to the current index
int min_ending_here = INT_MAX;
int min = INT_MAX; // absolute min
int min_second = INT_MAX - 1; // second min <- this is what you want
// traverse the array elements
for (int i = 0; i<n/*it is <, not <=*/; i++)
{
// if min_ending_here > 0, then it could not possibly
// contribute to the minimum sum further
if (min_ending_here > 0)
min_ending_here = arr[i];
// else add the value arr[i] to min_ending_here
else
min_ending_here += arr[i];
// update min and min_second
if (min_second > min_ending_here) {
if (min > min_ending_here) {
min_second = min;
min = min_ending_here;
}
else {
min_second = min_ending_here;
}
}
}
return min_second;
}
BTW, I think your code (the piece under //Below shows the sum of all contiguous sub arrays.) can not find all contiguous sub arrays.
An example, arr={1, 2, 3}, your code only consider {1,2,3}, {2,3} and {3} as contiguous sub arrays, while in fact {1,2} should also be considered.
Brutal force o(n^2) complexity (in C++ style not C style):
template<typename Container, typename Func>
void forEachSubrange(Container &container, Func &&f)
{
for (auto subBegin = container.begin(); subBegin != container.end(); ++subBegin)
{
auto subEnd = subBegin;
do {
++subEnd;
f(subBegin, subEnd);
} while (subEnd != container.end());
}
}
int secondSmallestSubrangeSum(const std::vector<int> &a)
{
int firstSum = 0; // empty sub range has zero sum
int secondSum = 0;
forEachSubrange(a, [&firstSum, &secondSum](auto b, auto e) {
auto sum = std::accumulate(b, e, 0);
if (sum < firstSum) {
secondSum = firstSum;
firstSum = sum;
} else if (sum < secondSum) {
secondSum = sum;
}
});
return secondSum;
}
I'm sure it is possible to achieve o(n).
https://wandbox.org/permlink/9cplKBIpfZBPpZ27
or more talkative https://wandbox.org/permlink/X21TdH6xtbMLpV19

code for generated numbers and how to show highest number to low

Need a program that generates 10 numbers from 1 to 6. code must be stored in an integer array and find out the highest, minimum value of the numbers generated and displayed in the code, also the overall summ of all the numbers generated from 1-6. All three functions must be returned in main..
ok! im awake now i can see that i can edite my original post so here goes my almost finished code.
#include<iostream>
#include<cstdlib>
#include<ctime>
using namespace std;
int main()
{
int highest = INT_MAX;
int lowest = INT_MIN;
int i = 0;
int sum = 0;
{
{
srand(time(0));
for (int i = 0; i < 10; i++)
cout << rand() % 6 + 1 << endl;
}
int myArray[10]{ 1,2,3,4,5,6 };
for (int i = 0; i < 10; i++)
myArray[i] = rand() % 6 + 1;
if (myArray[i] < lowest)
lowest = myArray[i];
if (myArray[i] > highest)
highest = myArray[i];
{
for (int i = 0; i < 10; i++)
sum = sum + rand() % 6 + 1;
cout << "The sum of all 10 numbers is " << sum << endl;
cout << "The largest value is = " << INT_MAX << endl;
cout << "The smallest value is = " << INT_MIN << endl;
}
return 1;
}
}
My problem here is that i cant define the int_max or int_min to display my highest numbers from 1-6 . i have tried other examples with int_m but it doesntn work. im hoping some u can give me a hint what im doing worng. Thank you
First of all, be careful with the indentation of your code.
Next, you need to keep track of every generated number by declaring an array.
srand(time(0));
//You have to include the limits library to use INT_MIN and INT_MAX
int highest = INT_MIN;
int lowest = INT_MAX;
int myArray[10]; //Array to hold 10 random numbers
for (int i = 0; i < 10; i ++)
{
myArr[i] = rand() % 6 + 1; // Generates a random number and stores it
if (myArr[i] < lowest)
lowest = myArr[i];
else if (myArr[i] > highest)
highest = myArr[i];
}
Now highest variable should hold the higest number generated and lowest variable should hold the lowest generated number.
And please next time please do more research before asking and be more specific.
I would avoid trying to use rand() or srand() there is a safer, more efficient and reliable way to generate random numbers. I will be showing you how to use one of many random number generators that are defined in the standard library. I will be using a random device to seed the engine or generator and the generator I will be using is the standard mersenne_twister_engine shown as mt19937. I will be using a uniform_int_distribution for the distribution type. There are many other types of generators that can be used, other types of distributions and a few other ways to seed these engines; another way to seed these besides a random_device is by using std::chrono time or steady clock system. You can find out more about these pseudo random number generators and distributions found here: cppreference.com to use these you will need to include the header file <random>.
I will be using a std::vector to contain the numbers generated and for this you will need to include <vector> although if you are required to use a basic default array you can easily replace the vector with an array of ints. I choose to use the std::vector<int> because of the already existing algorithms in the standard library that are available to you to perform the needed or required operations that you are asking for such as finding the minimum and maximum values and by adding all of the elements in that sequence or range of values. To use these algorithms you will need to include <algorithm> and <numeric>.
Here is the short program that I wrote strictly in the main function to show all the functionality that you are asking for. If you need to have these in separate functions that are called within the main then I leave that as a task for you to accomplish.
#include <iostream> // Output
#include <vector> // Container
#include <algorithm> // Algorithms
#include <numeric> // Other Needed Functions
int main() {
std::random_device rd; // Will be used to obtain a seed for the random number engine
std::mt19937 gen( rd() ); // Standard mersenne_twister_engine seeded with rd()
std::uniform_int_distribution<> dis( 1, 6 ); // Distribution Of Random Numbers in range of [1,6]
// Vector Or Array To Store Numbers
std::vector<int> numbers;
// Populate Vector
int n = 0;
for ( ; n < 10; ++n){
numbers.push_back( dis( gen ) );
}
// Display Random Values
n = 0;
for ( ; n < 10; ++n ) {
std::cout << numbers[n] << ", ";
}
std::cout << std::endl;
// Min & Max
std::vector<int>::iterator resultMin;
std::vector<int>::iterator resultMax;
resultMin = std::min_element(std::begin(numbers), std::end(numbers));
resultMax = std::max_element(std::begin(numbers), std::end(numbers));
// Sum
int sum = std::accumulate(numbers.begin(), numbers.end(), 0);
// Display Results
std::cout << "min value is: " << (*resultMin) << std::endl;
std::cout << "max value is: " << (*resultMax) << std::endl;
std::cout << "Sum of array is: " << sum << std::endl;
return 0;
}