Trying to develop a sort of permutation algorithm - c++

I want to develop the following put can't get it right.
I have a vector of N length. Each element can become 0 to K. Here N and K are given by the user. Now I'm trying to create a function in which I can walk through all possible solutions.
So let's say N is 4 and K = 2, then I want to loop through all possible permutations (?).
I want to fill a vector with 0000, test it then fill the vector with 1000, test it then 0100 etc.
It's important to know that 0100 and 0010 are different. As are 1100 and 0011 etc.
For extra notice this is what the loop should print (it really doesn't matter is 0001 or 1000 comes after 0000 etc as long as all different possible sequences come up).
0000, 1000, 0100, 0010, 0001, 1100, 1010, 1001, 1110, 1101, 0111, 0101, ....., 2012, 2211 etc..
I've tried a combination of for loops but can't really get it.
The application is in C++
Please help, tnx

I don't think permutation is the word you're looking for. You're talking about counting, so what you want to do is essentially increment the vector, just like if you were doing addition long hand as you did in first grade
First value 0 0 0 0
Add 1 1
=======
Second Value 0 0 0 1
Add 1 1
=======
Third Value 0 0 1 0
So you'd do somethign like this:
// returns false when you've seen all of the possible values for this vector
bool increment(std::vector<int> & vector, int k) {
for (int i = 0; i < vector.size(); ++i) {
int j = vector[i] + 1;
if (j <= k) {
vector[i] = j;
return true;
}
else vector[i] = 0;
// and carry a 1 by looping back again
}
return false;
}
This will return values in the following order, for k=1, assuming you start with the vector 0000: 1000, 0100, 1100, 0010, 1010, 0110, 1110, 0001, 1001, 0101, 1101, 0011, 1011, 0111, 1111.
(Picture counting in binary -- I've merely reversed each of the numbers to fit our ordinary view of a vector as going from left to right.)

Something like this comes to my mind
bool increase(vector<int> &d, int index, int k){
if(index == d.size()){
return false;
}
if(d[index] == k){
d[index] = 0;
increase(d, index+1, k);
}else{
d[index]++;
}
return true;
}
void printvector(vector<int> v){
cout<<" ";
for(int i=0;i<v.size();i++){
cout<<v[i];
}
}
int main(){
//int N, K predefined, and initialised.
vector<int> D(N, 0);
do{
printvector(d);
}while(increase(d, 0, K);
}

You might want a recursive solution to do it neatly.
Place the all the possibilities to the first element, and recursively invoke with decreasing size.
Pseudo code:
permutations(int n, int k, solution):
if (n==0): //base clause
print solution //or append to some extra data structure
return
for (i = 0 ; i <= k ; i++):
solution.append(i)
permutations(n-1,k,solution) //recursive call
solution.removeLast() //clean up environment before moving to the next possibility
invoke with permutations(n,k,v) - where n,k are your parameters and v is an empty std::vector
EDIT: C++ code:
void permutations(int n, int k,vector<int> &solution) {
if (n==0) { //base clause
print(solution);
return;
}
for (int i = 0 ; i <= k ; i++) {
solution.push_back(i);
permutations(n-1,k,solution); //recursive call
solution.pop_back(); //clean up environment before moving to the next possibility
}
}
a demo including the print() function can be found here

Related

Finding the number of sub arrays that have a sum of K

I am trying to find the number of sub arrays that have a sum equal to k:
int subarraySum(vector<int>& nums, int k)
{
int start, end, curr_sum = 0, count = 0;
start = 0, end = 0;
while (end < (int)nums.size())
{
curr_sum = curr_sum + nums[end];
end++;
while (start < end && curr_sum >= k)
{
if (curr_sum == k)
count++;
curr_sum = curr_sum - nums[start];
start++;
}
}
return count;
}
The above code I have written, works for most cases, but fails for the following:
array = {-1, -1, 1} with k = 0
I have tried to add another while loop to iterate from the start and go up the array until it reaches the end:
int subarraySum(vector<int>& nums, int k)
{
int start, end, curr_sum = 0, count = 0;
start = 0, end = 0;
while (end < (int)nums.size())
{
curr_sum = curr_sum + nums[end];
end++;
while (start < end && curr_sum >= k)
{
if (curr_sum == k)
count++;
curr_sum = curr_sum - nums[start];
start++;
}
}
while (start < end)
{
if (curr_sum == k)
count++;
curr_sum = curr_sum - nums[start];
start++;
}
return count;
}
Why is this not working? I am sliding the window until the last element is reached, which should have found a sum equal to k? How can I solve this issue?
Unfortunately, you did not program a sliding window in the correct way. And a sliding window is not really a solution for this problem. One of your main issues is, that you do not move the start of the window based on the proper conditions. You always sum up and wait until the sum is greater than the search value.
This will not really work. Especially for your example -1, -1, 1. The running sum of this is: -1, -2, -1 and you do not see the 0, although it is there. You may have the idea to write while (start < end && curr_sum != k), but this will also not work, because you handle the start pointer not correctly.
Your approach will lead to the brute force solution that typically takes something like N*N loop operations, where N is the size of the array. This, because we need a double nested loop.
That will of course always work, but maybe very time-consuming, and, in the end, too slow.
Anyway. Let us implement that. We will start from each value in the std::vector and try out all sub arrays starting from the beginning value. We must evaluate all following values in the std::vector, because for example the last value could be a big negative number and bring down the sum again to the search value.
We could implement this for example like the following:
#include <iostream>
#include <vector>
using namespace std;
int subarraySum(vector<int>& numbers, int searchSumValue) {
// Here we will store the result
int resultingCount{};
// Iterate over all values in the array. So, use all different start values
for (std::size_t i{}; i < numbers.size(); ++i) {
// Here we stor the running sum of the elements in the vector
int sum{ numbers[i] };
// Check for trivial case. A one-element sub-array does already match the search value
if (sum == searchSumValue) ++resultingCount;
// Now we build all subarrays beginning with the start value
for (std::size_t k{ i + 1 }; k < numbers.size(); ++k) {
sum += numbers[k];
if (sum == searchSumValue) ++resultingCount;
}
}
return resultingCount;
}
int main() {
vector v{ -1,-1,1 };
std::cout << subarraySum(v, 0);
}
.
But, as said, the above is often too slow for big vectors and there is indeed a better solution available, which is based on a DP (dynamic programming) algorithm.
It uses so-called prefix sums, running sums, based on the running sum before the current evaluated value.
We need to show an example. Let's use a std::vector with 5 values {1,2,3,4,5}. And we want to look subarrays with a sum of 9.
We can “guess” that there are 2 subarrays: {2,3,4} and {4,5} that have a sum of 9.
Let us investigate further
Index 0 1 2 3 4
Value 1 2 3 4 5
We can now add a running sum and see, how much delta we have between the current evaluated element and the left neighbor or over-next neighbor and so on. And if we have a delta that is equal to our search value, then we must have a subarray building this sum.
Running Sum 1 3 6 10 15
Deltas of 2 3 4 5 against next left
Running sum 5 7 9 against next next left
9 12 against next next next left
Example {2,3,4}. If we evaluate the 4 with a running sum of 10, and subtract the search value 9, then we get the previous running sum 1. “1+9=10” all values are there.
Example {4,5}. If we evaluate the 5 with a running sum of 15, and subtract the search value 9, then we get the previous running sum = 6. “6+9=15” all values are there.
We can find all solutions using the same approach.
So, the only thing we need to do, is to subtract the search value from the current running sum and see, if we have this running sum already calculated before.
Like: “Search-Value” + “previously Calculated Sum” = “Current Running Sum”.
Or: “Current Running Sum” – “Search-Value” = “previously Calculated Sum”
Again, we need to do the subtraction and check, if we already calculated such a sum previously.
So, we need to store all previously calculated running sums. And, because such a sum may appear more than one, we need to find occurrences of equal running sums and count them.
It is very hard to digest, and you need to think a while to understand.
With the above wisdom, you can draft the below potential solution.
#include <iostream>
#include <vector>
#include <unordered_map>
int subarraySum(std::vector<int>& numbers, int searchSumValue) {
// Here we will store the result
int resultingSubarrayCount{};
// Here we will stor all running sums and how ofthen their value appeared
std::unordered_map<int, int> countOfRunningSums;
// Continuosly calculating the running sum
int runningSum{};
// And initialize the first value
countOfRunningSums[runningSum] = 1;
// Now iterate over all values in the vector
for (const int n : numbers) {
// Calculate the running sum
runningSum += n;
// Check, if we have the searched value already available
// And add the number of occurences to our resulting number of subarrays
resultingSubarrayCount += countOfRunningSums[runningSum - searchSumValue];
// Store the new running sum. Respectively. Add 1 to the counter, if the running sum was alreadyy existing
countOfRunningSums[runningSum]++;
}
return resultingSubarrayCount;
}
int main() {
std::vector v{ 1,2,3,4,5 };
std::cout << subarraySum(v, 9);
}

Can someone please explain this approach to me?

I am working my way through the USACO training website. I found this question which requires us to find the minimum number of swaps in a three valued sequence. Although I have solved the problem with a O(n^2) solution, I was intrigued to find out this faster O(n) approach. However, I am finding it rather difficult to understand, being a beginner.
Here is the detailed problem statement and the best approach.
In this task the possible key values are the integers 1, 2 and 3. The
required sorting order is non-decreasing. However, sorting has to be
accomplished by a sequence of exchange operations. An exchange
operation, defined by two position numbers p and q, exchanges the
elements in positions p and q.
You are given a sequence of key values. Write a program that computes
the minimal number of exchange operations that are necessary to make
the sequence sorted.
#include <fstream>
using namespace std;
int min (int a, int b) { return a < b ? a : b; }
int max (int a, int b) { return a > b ? a : b; }
int main () {
int s[1024];
int n;
int sc[4] = {0};
ifstream fin("sort3.in");
ofstream fout("sort3.out");
fin>>n;
for (int i = 0; i < n; i++) {
fin>>s[i];
sc[s[i]]++;
}
int s12 = 0, s13 = 0, s21 = 0, s31 = 0, s23 = 0, s32 = 0;
for (int i = 0; i < sc[1]; i++){
if (s[i] == 2) s12++;
if (s[i] == 3) s13++;
}
for (int i = sc[1]; i < sc[1]+sc[2]; i++){
if (s[i] == 1) s21++;
if (s[i] == 3) s23++;
}
for (int i = sc[1]+sc[2]; i < sc[1]+sc[2]+sc[3]; i++){
if (s[i] == 1) s31++;
if (s[i] == 2) s32++;
}
fout<<min(s12, s21)+min(s13, s31)+min(s23, s32) +
2*(max(s12, s21) - min(s12, s21))<<endl;
return 0;
}
I got the part where we are taking the minimum of overlaps of 1s, 2s and 3s in their respective desired ranges [0->c1, c1->c1+c2, c1+c2->n]. However, I don't really understand the formula of 2*max(s12, s21) - min(s12, s21). Also why are we not considering s13, s31, s23, and s32 in the formula. I would like you to explain this to me as I don't intend to leave any unbridged gaps in my training. Thanks in Advance!
If we approach the problem from the other side and work out how to perform the swaps in an example we can see where the formula for the number of swaps comes from.
If we start with:
22121 23331 1231
s12 is 3
s13 is 0
s21 is 1
s23 is 3
s31 is 2
s32 is 1
Then swapping 1 and 2 with 1 swap (min(s12, s21)) gives:
12121 23332 1231
There are no swaps between 1 and 3 (min(s13, s31)).
Then swapping 2 and 3 with 1 swap (min(s23, s32)) gives:
12121 22332 1331
Now we're left with no more direct swaps, we need to swap twice to get the remaining elements into the correct locations. There are 2 1s in the wrong place, 2s in the wrong place and 2 3s in the wrong place, the number for each number must always be the same. The initial number of misplaced 1s was given by max(s12, s21), we've fixed min(s12, s21) of those leaving max(s12, s21) - min(s12, s21) still to fix. We'll need to perform 2 swaps to fix each incorrect element.
First swap the 2s where 1s should be with the 1s that are where the 3s should be, this takes 2 swaps giving:
11111 22332 2332
Now we can directly swap the 2s and 3s taking another 2 swaps giving the final result:
11111 22222 3333
Adding up the total number of swaps gives:
min(s12, s21) + min(s13, s31) + min(s23, s32) + 2*(max(s12, s21) - min(s12, s21))

How would one see if an array has consecutive numbers in C++?

This is basically the 8 Queens problem, but solving it with brute force in a 1D array. Say I have an array (named b) of size 8, with elements ranging from 0 to 7.
I initialize each index in the array with 8 for-loops, like this:
int b[8]={0};
int count = 0;
for(b[0] = 0; b[0]<8; b[0]++){
for(b[1] = 0; b[1]<8; b[1]++){
for(b[2] = 0; b[2]<8; b[2]++){
for(b[3] = 0; b[3]<8; b[3]++){
for(b[4] = 0; b[4]<8; b[4]++){
for(b[5] = 0; b[5]<8; b[5]++){
for(b[6] = 0; b[6]<8; b[6]++){
for(b[7] = 0; b[7]<8; b[7]++){
if(check(b))
{
count++;
print(b, count);
}
}}
}}
}}
}}
What this program is supposed to do is check every combination of numbers 0 to 7 and returning true for only certain conditions. There are supposed to be 92 solutions, if this sounds familiar, it should be - it is the 8 Queens problem using brute force. From here, this is what I understand are the conditions:
I want to be able to check if an array has a consecutive string of numbers; such as:
[0|5|7|1|2|3|6|4]
Here, the elements b[3], b[4] and b[5] are consecutive. I don't want that, I want to return false, since there is a consecutive string of numbers (basically queens are attacking)
I also do not want an array that has a string of backwards consecutive numbers like this:
[0|5|7|3|2|1|6|4]
And lastly, I do not want two or more numbers in indexes where it would make them look consecutive if we had simply changed then numbers between them:
[0|2|4|6|1|3|5|7]
Above is not acceptable because b[0] and b[7] are numbers in their "consecutive index" (because at least 2 queens are attacking each other).
[6|1|3|0|4|7|5|2]
Above is also not acceptable because b[1] and b[4] are also in consecutive indexes.
Similarly, when the values are swapped, the arrays
[7|2|4|6|1|3|5|0]
[6|4|3|0|1|7|5|2]
are also not acceptable. I also cannot have 2 or more of the same number.
The problem I am having is in creating the check function. I am told I need to use 1 for loop and 1 if-then statement. Can the check function just take the whole array as is? And if it does, how do look at the right-most element in the array, and check to see if it has consecutive indexes (queens are attacking it)? I've tried this:
bool ok(int board[8]){
for(int c = 7; c >= 0; c--){ //row check
for (int j=0; j<c; j++){
if (board[c]==board[j]){
return false;
}
}
for(int i = 1; i <= c; i++){
// diagonal check from top left to bottom right
if ((board[c]-i >= 0) && (board[c-i] == board[c]-i))
{return false;}
if ((board[c]+i <= 7) && (board[c+i] == board[c]+i))
{return false;}
// diagonal check from bottom left to top right
if ((board[c]-i >= 0) && (board[c-i] == board[c]+i))
{return false;}
if ((board[c]+i <= 7) && (board[c+i] == board[c]-i))
{return false;}
}
}
return true;
}
But not only does this not work (I get 300+ solutions), it is not as small as I am told it should be.
I think there is a little problem with your check of collisions in the diagonals: you've got 15 diagonals going each way (including the very short one-square diagonals in the corners), while your code checks only seven of each due to the board[c]+i <= 7 and board[c]-i >= 0 conditions.
Here is how you can simplify the checks and make them faster with the use of three boolean arrays: you've got 8 rows, 15 ascending diagonals, and 15 descending diagonals:
bool row[8];
bool ascending[15];
bool descending[15];
Initially, there are no queens in any of these rows/diagonals. As you go through the elements of board, do this:
for (int i = 0 ; i != 8 ; i++) {
// Check and mark the row
if (row[board[i]]) return false;
row[board[i]] = true;
// Check and mark the ascending diagonal
int ascIdx = board[i]+i;
if (ascending[ascIdx]) return false;
ascending[ascIdx] = true;
int descIdx = 7+board[i]-i;
if (descending[descIdx]) return false;
descending[descIdx] = true;
}
return true;

Generating all subsets from a single set

I was trying to understand the code to generate all the subsets from one set. Here is the code
#include <stdio.h>
/* Applies the mask to a set like {1, 2, ..., n} and prints it */
void printv(int mask[], int n) {
int i;
printf("{ ");
for (i = 0; i < n; ++i)
if (mask[i])
printf("%d ", i + 1); /*i+1 is part of the subset*/
printf("\\b }\\n");
}
/* Generates the next mask*/
int next(int mask[], int n) {
int i;
for (i = 0; (i < n) && mask[i]; ++i)
mask[i] = 0;
if (i < n) {
mask[i] = 1;
return 1;
}
return 0;
}
int main(int argc, char *argv[]) {
int n = 3;
int mask[16]; /* Guess what this is */
int i;
for (i = 0; i < n; ++i)
mask[i] = 0;
/* Print the first set */
printv(mask, n);
/* Print all the others */
while (next(mask, n))
printv(mask, n);
return 0;
}
I am not understand the logic behind this line for (i = 0; (i < n) && mask[i]; ++i) inside the next function. How is the next mask being generated here?
Code and algorithm looked here:
http://compprog.wordpress.com/2007/10/10/generating-subsets/
That is simply an implementation of counting in binary. The basic idea is to change the least-significant (last) zero to a one, and change all the ones after it to zeroes. The "next" mask will be "one more" than the previous if interpreted as a binary number.
Because the array is arranged with the one's place first, it looks backwards from traditional numeric notation.
Instead of using an array of Boolean values, it could just as well use the bits in the binary representation of one number and the ++ operator.
int next(int &mask, int n) { // using C++ reference
if ( mask == ( 1u << n ) - 1 ) return 0;
++ mask;
return 1;
}
void printv(int mask, int n) {
int i;
printf("{ ");
for (i = 0; i < n; ++i)
if (mask & ( 1 << i ) )
printf("%d ", i + 1); /*i+1 is part of the subset*/
printf("\\b }\\n");
}
I've used a little C++ since you tagged the question as such, but the posted code is plain C.
Last year I participated in the C language contest of the 6th ITAT competition where I solved the second problem by generating all comabinations with the help of a mask (though, it might not be an optimal solution to that problem.)
When you try to derive all the subsets of {a,b,c}, you do it this way:
You may or may not take the first element a.
May or may not take the 2nd element b.
Same for c.
So you wind up with a set of 3 take-or-not-take choices. This can be represented in binaries or boolean values: represent taking by 1, and not taking by 0.
You get the following eight masks: (by the order of a,b,c)
000 100 010 110 001 101 011 111
To generate the next mask of 110:
element 0 is 1. Switch it to 0.
element 1 is 1. Switch it to 0.
element 2 is 0. Switch it to 1.
now you have 001 which is the next mask, which generates subset {c}.
for (i = 0; (i < n) && mask[i]; ++i) does exactly that.
start at element 0.
while (i doesn't exceed your mask length AND element i is 1)
do the body code which flips i to 0, and ++i (go to next element). goto 2 (check).
If the current mask is 111 (the last mask), the next() function simply returns 1 to indicate END.
(P.S. a non-zero integer always represents true.)
The loop in questions starts at the beginning of the array and sets all 1s to 0s until a 0 in encountered. The next statement sets this 0 to a 1 (if possible). So what happens is: 0,0,0 -> 1,0,0 -> 0,1,0 -> 1,1,0 -> 0,0,1... I am not a hardcore C programmer but I think this could have been done easier by using a bit field and incrementing by 1 iteratively.
for (i = 0; (i < n) && mask[i]; ++i)
for:
start at 0 and increment i by 1 each time
don't stop while i is less than n and the bit in the mask array at position i is set
it's straightforward really: 3 parts to a for statement: initial state; end condition; operation.
So if you can understand for (i=0; i < 5; i++) means start at 0 and increment i by 1 each time until it fails to be less than 5, you can understand the more complex for loop you asked about.
in this case, it's going through the loop looking for the first element of the mask that is not set, clearing each element as it goes, then it performs some other operation - namely if there was no mask bits set, and it reached the end of the array. Seems to me like a simple way of setting only one element of an array to 1, in sequence to get the result: 100, 010, 001

Permuting All Possible (0, 1) value arrays

I am having writing an algorithm to generate all possible permutations of an array of this kind:
n = length
k = number of 1's in array
So this means if we have k 1's we will have n-k 0's in the array.
For example:
n = 5;
k = 3;
So obviously there are 5 choose 3 possible permutations for this array because
n!/(k!(n-k)!
5!/(3!2!) = (5*4)/2 = 10
possible values for the array
Here are all the values:
11100
11010
11001
10110
10101
10011
01110
01101
01011
00111
I am guessing i should use a recursive algorithms but i am just not seeing it. I am writing this algorithm in C++.
Any help would be appreciated!
Just start with 00111 and then use std::next_permutation to generate the rest:
#include <algorithm>
#include <iostream>
#include <string>
int main()
{
std::string s = "00111";
do
{
std::cout << s << '\n';
}
while (std::next_permutation(s.begin(), s.end()));
}
output:
00111
01011
01101
01110
10011
10101
10110
11001
11010
11100
You can split up the combinations into those starting with 1 (n-1, k-1) and those starting with 0 (n-1, k).
This is essentially the recursive formula for the choose function.
What you want is actually a combination since the 1's and 0's are indistinguishable and therefore their order doesn't matter (e.g. 1 1 1 vs 1 1 1).
I recently had to rewrite a combination function myself because my initial version was written recursively in a very straightforward way (pick an element, get all the combinations of the remaining array, insert the element in various places) and did not perform very well.
I searched StackOverflow and just seeing the pictures in this answer lit up the iconic lightbulb over my head.
If you want to do this recursively, observe that the set of permutations you want is equal to all the ones that start with "1", together with all the ones that start with "0". So in calculating (n,k), you will recurse on (n-1,k-1) and (n-1,k), with special cases where k = 0 and k = n.
This recursion is the reason that the binomial coefficients appear as the values in Pascal's triangle.
Homework and recursive algorithm? OK, here you go:
Base case:
You have two elements, name them "a" and "b" and produce the concatenations ab, then ba.
Step: If your second Element is longer than 1, split it up in first field/letter and the other part, and pass that recursively as parameters to the function itself.
That will work for any strings and arrays.
Its about 0-1 permutations, so probably its much more eficient to iteratively increment an integer and in case it has desired bits count, print out its binary representation.
Here a sketch:
void printAllBinaryPermutations(int k, int n)
{
int max = pow(2, n) - 1;
for(int i=0; i<=max;i++)
{
if(hasBitCountOf(i, k)) // i has k 1's?
{
printAsBinary(i, n);
}
}
}
bool hasBitCountOf(int v, int expectedBitCount)
{
int count = 0;
while(v>0 && count<= expectedBitCount)
{
int half = v >> 1;
if(half<<1 != v)
{
// v is odd
count++;
}
v = half;
}
return count==expectedBitCount;
}
void printAsBinary(int number, int strLen)
{
for(int i=strLen-1; i>=0; i--)
{
bool is0 = (number & pow(2,i)) == 0;
if (is0)
{
cout<<'0';
}
else
{
cout<<'1';
}
}
cout<<endl;
}
I am not sure this helps, plus it is just some weird pseudocode, but this should give you the desired ouput.
permutation (prefix, ones, zeros, cur) {
if (ones + zeros == 0) output(cur);
else {
if (cur != -1) prefix = concat(prefix,cur);
if (ones > 0) permutation(prefix, ones - 1, zeros, 1);
if (zeros > 0) permutation(prefix, ones, zeros - 1, 0);
}
}
permutation(empty, 3, 2, -1);
greetz
back2dos