Limit chunks of combination in c++ - c++

I modified a code I've found on the internet to fit my needs. It calculates and prints all possible combinations of r elements in an array given size of N. Here's the code:
#include <iostream>
#include <vector>
void combinationUtil(std::vector<int> arr, std::vector<int> data, int start, int end, int index, int r);
void printCombination(std::vector<int> arr, int n, int r)
{
std::vector<int> data;
data.assign(r, 0);
combinationUtil(arr, data, 0, n-1, 0, r);
}
void combinationUtil(std::vector<int> arr, std::vector<int> data, int start, int end, int index, int r)
{
if (index == r)
{
for (int j = 0; j < r; j++)
std::cout << data.at(j) << " ";
std::cout << std::endl;
return;
}
for (int i = start; i <= end && end - i + 1 >= r - index; i++)
{
data.at(index) = arr.at(i);
combinationUtil(arr, data, i+1, end, index+1, r);
}
}
int main()
{
std::vector<int> arr = {1, 2, 3, 4, 5};
int r = 3;
int n = arr.size();
printCombination(arr, n, r);
}
The output of it is:
1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
2 3 4
2 3 5
2 4 5
3 4 5
I can modify the start value to 1 so the output can start from value 2 like so:
2 3 4
2 3 5
2 4 5
3 4 5
How can I achieve a similar effect for the end. For example if I wanted it to end before calculating combinations starting with value 2. I want to see a result like:
1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
I want to do this so I can utilize parallelizations for a larger scale function.
I hope I could relay the idea clear enough. Thanks in advance. (Code compiles with some casting warnings. I just left it like this for an easier read for the reader.)

I solved the issue by modifying another combination method I found on this site.
Here's the code for it:
#include <iostream>
#include <vector>
using namespace std;
vector<int> people;
vector<int> combination;
void pretty_print(const vector<int>& v) {
static int count = 0;
cout << "combination no " << (++count) << ": [ ";
for (int i = 0; i < v.size(); ++i) { cout << v[i] << " "; }
cout << "] " << endl;
}
void go(int offset, int k, int end, bool outermost = true) {
if (k == 0) {
pretty_print(combination);
return;
}
for (int i = offset; i <= people.size() - k; ++i) {
combination.push_back(people[i]);
go(i+1, k-1, end, false);
combination.pop_back();
if(outermost && i == end) return;
}
}
int main() {
int k = 3, end = 1;
people = {1, 2, 3, 4, 5};
go(0, k, end);
return 0;
}
offset controls start and end controls the end.
For loop going on at the outside most layer controls the first element selected for the combination and it progresses as the function recurses.
If statement inside the for loop checks if the wanted line is reached and returns the function prematuraly as needed.

Related

Permutations of a specific set of numbers from n to m

#include <iostream>
using namespace std;
int n, m, x[20], p[20];
void display(){
for(int i = 1 ; i <= n; ++i)
cout << x[i] << ' ';
cout << "\n";
}
void bkt(int k){
for(int i = n; i <= m; ++i)
if(!p[i]){
x[k] = i;
p[i] = 1;
if(k<n)
bkt(k+1);
else
display();
p[i] = 0;
}
}
int main()
{ cin >> n >> m;
bkt(1);
return 0;
}
This code should do the permutations from n to m, but it doesn't work and I don't know what I did wrong. I tried a set of examples like 4 and 6, and it should show
4 5 6
4 6 5
5 4 6
5 6 4
6 4 5
6 5 4
but it doesn't show anything in the console, just returns 0.
There's a number of issues with the code, but you can solve the problem in the following way:
cin >> n >> m; // get range
Then create a vector of the appropriate size
std::vector<int> v(m - n + 1);
and then fill it with the needed values
std::iota(std::begin(v), std::end(v), n);
and then generate all permutations in a loop
do {
// ...
} while(std::next_permuation(std::begin(v), std::end(v));

Generating the worst case fot quicksort C++

I need to create the worst test case for standard quicksort: an array from 1 to N with given size (N can be from 1 to 70000). The key element is the one in the middle. I wrote a recursive function that puts the largest element in the middle (so the algorithm has to compare every element on the left with it) and then splits the array into two parts to put the next biggest elements in the middle of resulting parts. However, my code doesn't pass every case. What could be a problem here?
P. S. my goal is to make the quicksort to do as many comparisons as possible
#include <iostream>
#include <fstream>
using namespace std;
int antiqs(int* array, int start, int end, int maxElement, int* time){
if(end - start < 2) {
return maxElement - *time;
}
int middle = (start + end) / 2;
array[middle] = maxElement - *time;
*time = *time + 1;
antiqs(array, start, middle - 1, maxElement, time);
antiqs(array, middle + 1, end, maxElement, time);
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int n;
ifstream fileIn("antiqs.in.txt");
fileIn >> n;
fileIn.close();
int array[n];
for(int i = 0; i < n; i++){
array[i] = 0;
}
int time = 0;
int max = antiqs(array, 0, n-1, n, &time);
ofstream fileOut("antiqs.out.txt");
for(int i = 0; i < n; i++){
if(array[i] == 0){
array[i] = max;
max = max - 1;
}
fileOut << array[i] << " ";
}
fileOut.close();
return 0;
}
Generate a pattern of increasing even numbers followed by decreasing odd numbers. For example:
2 4 6 8 10 7 5 3 1
2 4 6 8 7 5 3 1
2 4 6 7 5 3 1
2 4 6 5 3 1
2 4 5 3 1
2 4 3 1
2 3 1
2 1
1
Example Lomuto partition scheme that uses middle element for pivot:
void QuickSort(int a[], int lo, int hi)
{
while (lo < hi){
std::swap(a[(lo+hi)/2], a[hi]); // use mid point for pivot
int p = a[hi];
int i = lo; // Lomuto partition
for (int j = lo; j < hi; ++j){
if (a[j] < p){
std::swap(a[j], a[i]);
++i;
}
}
std::swap(a[i], a[hi]);
if(i - lo <= hi - i){ // recurse on smaller, loop on larger
QuickSort(a, lo, i-1);
lo = i+1;
} else {
QuickSort(a, i+1, hi);
hi = i-1;
}
}
}

Unintended behavior in c++ when passing in an incremented integer to a recursive function

The code itself accepts N and M from standard input and prints M-length combinations from 1 to N.
#include <iostream>
void print(int *arr, int size)
{
for (int i=0; i<size; i++)
std::cout << arr[i] << " ";
std::cout << "\n";
}
bool is_found(int *arr, int size, int num)
{
for (int i=0; i<size; i++)
{
if (num == arr[i])
return true;
}
return false;
}
void recurse(int *arr, int n, int m, int cur)
{
if (cur >= m)
print(arr, m);
else
{
for (int i=1; i<=n; i++)
{
if (is_found(arr, cur + 1, i))
continue;
arr[cur] = i;
recurse(arr, n, m, cur + 1);
}
}
}
int main()
{
int *arr;
int n;
int m;
int temp;
std::cin >> n >> m;
arr = new int[n];
for (int i=0; i<n; i++)
arr[i] = 0;
recurse(arr, n, m, 0);
}
Eg.
input: 4 4
output:
1 2 3 4
1 2 4 3
1 3 2 4
1 3 4 2
1 4 2 3
1 4 3 2
2 1 4 3
2 3 1 4
2 3 4 1
2 4 1 3
2 4 3 1
3 1 2 4
3 1 4 2
3 2 1 4
3 2 4 1
3 4 1 2
3 4 2 1
4 1 3 2
4 2 1 3
4 2 3 1
4 3 1 2
4 3 2 1
The code above works as intended.
However, in the recurse function, changing this part of the code results in unexpected behavior.
arr[cur] = i;
recurse(arr, n, m, cur + 1);
void recurse(int *arr, int n, int m, int cur)
{
if (cur >= m)
print(arr, m);
else
{
for (int i=1; i<=n; i++)
{
if (is_found(arr, cur + 1, i))
continue;
// option 1 (original, works)
arr[cur] = i;
recurse(arr, n, m, cur + 1);
// option 2 (doesn't work)
arr[cur++] = i;
recurse(arr, n, m, cur);
// option 3 (doesn't work)
arr[cur] = i;
cur = cur + 1;
recurse(arr, n, m, cur);
This is the output when using option 2 and option 3
input: 4 4
output:
1 2 3 4
1 2 4 3
1 3 2 4
1 3 4 2
My question is, aren't the three options written above equivalent? I don't understand why option 1 works as intended and options 2 and 3 don't. Why does passing in the value cur + 1 to the recursive function work, but changing the value of cur before passing, doesn't?
My best guess is that it has something to do with recursion and using the same array for the recursive call, or perhaps the problem is from a completely different part of the code. But I really have no idea why this is happening.
Any help is greatly appreciated! Thank you in advance!
This:
// option 1 (original, works)
arr[cur] = i;
recurse(arr, n, m, cur + 1);
Does not modify cur. The loop continues with the next loop and the value of cur is the same in the next iteration. On the other hand, this
// option 2 (doesn't work)
arr[cur++] = i;
recurse(arr, n, m, cur);
// option 3 (doesn't work)
arr[cur] = i;
cur = cur + 1;
Both modify cur and the value wont be the same in the next iteration. I suppose the confusion is caused by recursion, but consider the same without recursion:
int cur = 0;
for (int i=1; i<=n; i++)
{
arr[cur] = i;
}
vs
int cur = 0;
for (int i=1; i<=n; i++)
{
cur = cur + 1;
arr[cur] = i;
}
Would you expect this two to be identical?

Can't get my sort function to use print method to show iterations

I want displayArray on line 69 to work every time it iterates to show the changes of the insertion sort. I haven't been able to get it to work and have been spinning my wheels for a bit. Please help/explain. Thank you in advance.
This is what my output should look like:
Expected Output:
Enter up to 20 nonnegative whole numbers.
Mark the end of the list with a negative number.
3 7 4 9 5 2 6 1 -1
3 7 4 9 5 2 6 1
3 4 7 9 5 2 6 1
3 4 7 9 5 2 6 1
3 4 5 7 9 2 6 1
2 3 4 5 7 9 6 1
2 3 4 5 6 7 9 1
1 2 3 4 5 6 7 9
In sorted order the numbers are:
1 2 3 4 5 6 7 9
Code:
#include <iostream>
using namespace std;
const int MAX_SIZE = 20;
// Fills the array a[] with data from the user for a[0] through a[numberUsed -1].
// Since the user will not necessarily use up all the allocated entries in the array,
// the function will set the actual number of entries used in the "numberUsed"
// reference variable.
void fillArray(int a[], int arraySize, int& numberUsed);
// Sorts the array a[] such that a[0] <= a[1] <= ... <= a[numberUsed - 1].
void insert_sort(int a[], int numberUsed);
// Interchanges the values of v1 and v2.
void swapValues(int& v1, int& v2);
// Displays the contents of the array
void displayArray(const int a[], int numberUsed);
int main( )
{
cout << "This program sorts numbers from lowest to highest.\n";
int sampleArray[MAX_SIZE] = {0};
int numberUsed = 0;
fillArray(sampleArray, MAX_SIZE, numberUsed);
insert_sort(sampleArray, numberUsed);
cout << "In sorted order the numbers are:\n";
displayArray(sampleArray, numberUsed);
return 0;
}
void fillArray(int a[], int arraySize, int& numberUsed)
{
cout << "Enter up to " << arraySize << " nonnegative whole numbers.\n"
<< "Mark the end of the list with a negative number.\n";
int next = 0;
int index = 0;
cin >> next;
while ((next >= 0) && (index < arraySize))
{
a[index] = next;
index++;
cin >> next;
}
numberUsed = index;
}
void insertion_sort (int a[], int numberUsed){
int j, temp;
for (int i = 0; i < numberUsed; i++){
j = i;
while (j > 0 && a[j] < a[j-1]){
temp = a[j];
a[j] = a[j-1];
a[j-1] = temp;
j--;
}
displayArray(a,numberUsed);
}
}
void swapValues(int& v1, int& v2)
{
int temp;
temp = v1;
v1 = v2;
v2 = temp;
}
void displayArray(const int a[], int numberUsed)
{
for (int index = 0; index < numberUsed; index++)
{
cout << a[index] << " ";
}
cout << endl;
}

Generate subsets of elements from vector (NO NESTED LOOP)

Let v = {1,2,3,4,5,6}. I want to generate by using v the following sets:
1 2 3 4 5 6
2 1 3 4 5 6
3 1 2 4 5 6
4 1 2 3 5 6
5 1 2 3 4 6
6 1 2 3 4 5
To achieve this goal I am using the following code, with a nested for loop:
#include<vector>
#include<iostream>
using namespace std;
int main()
{
vector<int> v{1,2,3,4,5,6};
for(unsigned int i = 0; i < v.size(); i++)
{
cout << v[i] <<",";
for(unsigned int j = 0; j < v.size(); j++)
{
if(i != j)
cout << v[j] <<",";
}
cout << endl;
}
return 0;
}
Is there a better approach that can be used in order to generate the previous sets. At least not O(n^2).
For an input list of size n, your output will always consist of n*n numbers. You cannot do better than O(n^2).
However, it seems to me that you merely swap the first and the first element, then the first and the second, then the first and the third etc..
You can hide the inner loop which prints a particular subset with an algorithm though, like in
#include <algorithm>
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v {1, 2, 3, 4, 5, 6};
for ( auto it = v.begin(); it != v.end(); ++it ) {
std::iter_swap( v.begin(), it );
std::copy( v.begin(), v.end(), std::ostream_iterator<int>( std::cout, "," ) );
std::cout << '\n';
}
}
To understand the lower bounds in your algorithm; Lets look at the transformation between the input and the output.
You are starting with a list of N elements and you end up with a list of [N x (N - 1)] elements.
Ignoring the logic to generate the output, the act of outputting itself is O(N * (N - 1)) => O(n2).
In other words, you are outputting NxN items per the intial input on N. This will be O(n2) by definition.
Here the inner loop is only used to print results:
int main()
{
vector<int> v{1,2,3,4,5,6};
for(unsigned int i = 0; i < v.size(); i++)
{
int t = v[0];
v[0] = v[i];
v[i] = t;
cout << v[0];
for(unsigned int j = 1; j < v.size(); j++)
{
cout << "," << v[j];
}
cout << endl;
}
return 0;
}