combination of n distinct numbers - algorithm

I have a set of n case in the format a b what I have to do is I have to form number of distinct combination of numbers from a,b. for e.g.,
suppose n=4 and a,b are are follow
1 2
3 1
2 4
3 2
Now total there are 4 distinct number by seeing a,b, they are(1,2,3,4)
and two combination of all distinct numbers can be formed, they are (1,3,4,2) and (2,1,4,3) as follow :-
1 2
|
3 1
\
2 4
|
3 2
and
1 2
|
3 1
|
2 4
/
3 2
My problem is I am unable to think how to code, as n<=50 and a,b<=16 so I am not sure that how many distinct number can be there, if there are 16 numbers then I have to find all possible combination of 16 numbers, so guide me through this.

To form a list of distinct numbers just use a "unique set" and keep inserting all the numbers to it. In C++, std::set by definition stores only unique numbers.
To find the number of combinations of distinct sequences, you will have to keep a list of "candidate lists" and keep inserting numbers in them if they already don't have those numbers, else delete that particular candidate list.
Full code in C++:
#include <iostream>
#include <vector>
#include <set>
using namespace std;
int main() {
int n = 4;
set<int> uniqueNumbers; // ordered set of unique numbers
vector< set<int> > possibleLists( 1 );
set<int>::iterator it;
for ( int i = 0; i < n; i++ ) {
int num1;
int num2;
cin >> num1 >> num2;
// numbers will be inserted if not already present in set (by definition)
uniqueNumbers.insert( num1 );
uniqueNumbers.insert( num2 );
// make a copy for a possible new branch
vector< set<int> > possibleListsCopy( possibleLists );
//int size1 = possibleLists.size();
for ( int j = 0; j < possibleLists.size(); j++ ) {
it = possibleLists[j].find( num1 );
if ( it == possibleLists[j].end() ) {
possibleLists[j].insert( num1 ); // insert if not found
//cout << "inserted1 "<<endl;
}
else {
// erase this possible combination
possibleLists[j].clear();
possibleLists.erase( possibleLists.begin() + j );
j--;
}
}
//int size2 = possibleListsCopy.size();
for ( int j = 0; j < possibleListsCopy.size(); j++ ) {
;
it = possibleListsCopy[j].find( num2 );
if ( it == possibleListsCopy[j].end() ) {
possibleListsCopy[j].insert( num2 ); // insert if not found
}
else {
// erase this possible combination
possibleListsCopy[j].clear();
possibleListsCopy.erase( possibleListsCopy.begin() + j );
j--;
}
}
// concatenate both set of lists.
possibleLists.insert( possibleLists.end(),
possibleListsCopy.begin(),
possibleListsCopy.end() );
}
cout << " The unique list: ";
//output the unique list.
for ( it = uniqueNumbers.begin(); it != uniqueNumbers.end(); it++ )
cout << *it << " ";
/*cout << endl << endl;
cout << "Possible Lists:" << endl;
for ( int i = 0; i < possibleLists.size(); i++ ) {
for ( it = possibleLists[i].begin(); it != possibleLists[i].end(); it++ )
cout << *it << " ";
cout << endl;
}*/
cout << endl << "Total number of combinations: "
<< possibleLists.size() << endl;
return 0;
}
Input:
1 2
3 1
2 4
3 2
Output:
The unique list: 1 2 3 4
Total number of combinations: 2

Recursion is probably the easiest route when solving combinatorial problems like this one. The idea is that you consider all the possibilities for the current item, then pass off the rest of the work by recursing on the remaining items. In this case you need to pass along a bit of extra information about what items not to use.
It works something like this:
def DistinctChooseFromEach(listOfChoicePairs, alreadyUsed = {}):
if listOfChoicePairs is empty: return []
for value in listOfChoicePairs[0]:
if value in alreadyUsed: continue;
newUsed = union(alreadyUsed, value)
remainingChoices = listOfChoicePairs[1:];
tails = DistinctChooseFromEach(remainingChoices, newUsed)
for tail in tails:
yield concat(value, tail)

Related

Finding all possible unique combinations of numbers to reach a given sum

We have a list of numbers, let's say: [ 2, 3, 5 ]
and we have a targetSum, let's say: 8
Our goal, then, is to pick numbers from the list in such a way that the sum of the numbers would lead to targetSum
I'll explain my code first, I wrote a simple c++ code for the same, it uses recursion and backtracking ( without memoization ). It does the following:
We subdivide our original problem by reducing the targetSum by each number at each recursion
Visualizing this in the form of a tree is useful, we also keep track of what number's we have substracted so far, and we keep pushing and popping accordingly
Once we hit the base case of 0, meaning it's possible to create the sum, we make a note of the current numbers we have recursed
This process goes on until we have gone through all of the possibilities
Code:
#include<iostream>
#include<vector>
using namespace std;
bool bestSum( int targetSum, vector<int> &holder, vector<vector<int>> &combinations,
vector<int> &path )
{
if( targetSum == 0 )
{
combinations.push_back( path );
return true;
}
if( targetSum < 0 )
{
return false;
}
bool possible = false;
for( int i = 0; i < holder.size(); i++ )
{
int remainder = targetSum - holder[i];
path.push_back(holder[i]);
cout << "After pushing:";
for( int j = 0; j < path.size(); j++ )
{
cout << path[j] << " ";
}
cout << endl;
bool verdict = bestSum( remainder, holder, combinations, path );
if( verdict == true )
{
possible = true;
}
path.pop_back();
cout << "After popping:";
for( int j = 0; j < path.size(); j++ )
{
cout << path[j] << " ";
}
cout << endl;
}
return possible;
}
int main()
{
vector<int> holder = { 2, 3, 5 };
int targetSum = 8;
vector<vector<int>> combinations;
vector<int> path;
bool verdict = bestSum( targetSum, holder, combinations, path );
for( int i = 0; i < combinations.size(); i++ )
{
for( int j = 0; j < combinations[i].size();j++)
{
cout << combinations[i][j] << " ";
}
cout << endl;
}
return 0;
}
(ignoring the printing statements) Talking about time complexity, it should be: exponential, without memoization
And at most small degree polynomial, with memoization
Combing back to the original problem, currently my code produces all of the possible combinations, for example, with the numbers list and targetSum presented at the start of this article, we would get: 2,3,3 and 3,3,2 as two different combinations. But we know that they aren't unique
My question is, is it possible to find all unique combination of numbers whilst keeping the logic of my code consistent?

Minimum number of operations to get from source to target.

I came across this question during an interview -
Convert a number source to target in the minimum number of operations.
Allowed Operations
Multiplied by 2.
Addition by 1.
subtraction by 1.
0 < source, target <= 1000.
I tried going the naive recursive route(O(3^n)) ie. subtract 1, add 1 and multiply by 2 at each level to try and find a solution that I could extend to Dynamic Programming but couldnt because of an infinite loop.
//Naive approach Via Recursion
int minMoves(int source, int target){
if(source <1 || source > target){
return -1;
}
int moves =0;
// Potential infinite loop - consider 3,6-> 2,6- >1,6->(0,6)x (2,6)->1,6->(0,6)x (1,6)->(0,6)x (2,6)->1,6..
int movesLeft = minMoves(source -1, target) ==-1? Integer.MAX_VALUE:minMoves(source -1, target);
int movesRight = minMoves(source +1, target) ==-1? Integer.MAX_VALUE:minMoves(source +1, target);
int moves2X = minMoves(2*source, target) ==-1? Integer.MAX_VALUE:minMoves(2*source, target);
moves = 1+ Math.min(Math.min(movesRight,movesLeft), moves2X);
return moves;
}
Any ideas on how I can tweak my solution? Or possibly a better way to solve it?
If you think about your solution like a graph traversal, where each node is an intermediate value you can produce, your recursive solution is like a depth first search (DFS). You'll have to fully expand until you've tried all solutions from that "branch" of the search space before you can proceed anywhere else. If you have an infinite loop, this means it will never terminate even if a shorter path exists, and even if you don't have an infinite loop, you still have to search the rest of the solution space to make sure its optimal.
Instead, consider an approach similar to breadth first search (BFS). You expand outward uniformly, and will never search a path longer than the optimal solution. Just use FIFO queue to schedule which node to access next. This is the approach I've taken with my solver.
from queue import Queue
def solve(source, target):
queue = Queue()
path = [source]
queue.put(path)
while source != target:
queue.put(path + [source * 2])
queue.put(path + [source + 1])
queue.put(path + [source - 1])
path = queue.get()
source = path[-1]
return path
if __name__ == "__main__":
print(solve(4,79))
One way in which you can speed up(and possibly fix) this code, while maintaining the recursive implementation, is to use memoization.
The issue here is that you are recalculating the same value many times. Instead you can use a map to store the results that you already calculated, and reuse them when you need it again.
This problem can be solved constructively. First, the easy cases. If s=t, the answer is 0. If s > t, the answer is s-t because subtraction by 1 is the only operation that lowers s, and the other two can only increase the number of subtractions required.
Now let's assume s < t. Since s>0 is given, doubling will always be the fastest way to increase (if s is 1, it's tied with incrementing). So if the challenge was to make s >= t, the answer would always be the number of doublings required to do that. This procedure may overshoot t, but the first doubling greater than t and the last doubling not greater than t must be within a factor of 2 of t.
Let's look at the effect of when we do an addition or subtraction. First, look only at addition:
(((s*2) * 2) * 2) + 1 = 8s + 1
vs:
((((s+1)*2) * 2) * 2) = 8s + 8
Putting an addition before n doublings makes the final result 2^n bigger. So consider if s is 3 and t is 8. The last double not bigger than 8 is 6. This is 2 off, so if we put an addition 1 double before the last double, we get what we want: (3+1) * 2. Alternatively we could try overshooting to the first double greater than 8, which is 12. This is 4 off, so we need to put a subtraction two doublings before the last : (3-1)*2*2 = 8
In general if we are x below the target, we need to put a +1 at n doublings before the last if the binary representation of x has a 1 at the nth place.
Similarly, if we are x above the target, we do likewise with -1's.
This procedure won't help for the 1's in x's binary representation that are at a position more than the number of doublings there are. For example, if s = 100, t=207, there is only 1 doubling to do, but x is 7, which is 111. We can knock out the middle one by doing an addition first, the rest we have to do one by one (s+1)*2 + 1 + 1 + 1 + 1 + 1.
Here is an implementation that has a debug flag that also outputs the list of operations when the flag is defined. The run time is O(log(t)):
#include <iostream>
#include <string>
#include <sstream>
#define DEBUG_INFO
int MinMoves(int s, int t)
{
int ans = 0;
if (t <= s)
{
return s - t; //Only subtraction will help
}
int firstDoubleGreater = s;
int lastDoubleNotGreater = s;
int nDouble = 0;
while(firstDoubleGreater <= t)
{
nDouble++;
lastDoubleNotGreater = firstDoubleGreater;
firstDoubleGreater *= 2;
}
int d1 = t - lastDoubleNotGreater;
int d2 = firstDoubleGreater - t;
if (d1 == 0)
return nDouble -1;
int strat1 = nDouble -1; //Double and increment
int strat2 = nDouble; //Double and decrement
#ifdef DEBUG_INFO
std::cout << "nDouble: " << nDouble << "\n";
std::stringstream s1Ops;
std::stringstream s2Ops;
int s1Tmp = s;
int s2Tmp = s;
#endif
int mask = 1<<strat1;
for(int pos = 0; pos < nDouble-1; pos++)
{
#ifdef DEBUG_INFO
if (d1 & mask)
{
s1Ops << s1Tmp << "+1=" << s1Tmp+1 << "\n" << s1Tmp+1 << "*2= " << (s1Tmp+1)*2 << "\n";
s1Tmp = (s1Tmp + 1) * 2;
}
else
{
s1Ops << s1Tmp << "*2= " << s1Tmp*2 << "\n";
s1Tmp = s1Tmp*2;
}
#endif
if(d1 & mask)
strat1++;
d1 = d1 & ~mask;
mask = mask >> 1;
}
strat1 += d1;
#ifdef DEBUG_INFO
if (d1 != 0)
s1Ops << s1Tmp << " +1 " << d1 << " times = " << s1Tmp + d1 << "\n";
#endif
mask = 1<<strat2;
for(int pos = 0; pos < nDouble; pos++)
{
#ifdef DEBUG_INFO
if (d2 & mask)
{
s2Ops << s2Tmp << "-1=" << s2Tmp-1 << "\n" << s2Tmp-1 << "*2= " << (s2Tmp-1)*2 << "\n";
s2Tmp = (s2Tmp-1)*2;
}
else
{
s2Ops << s2Tmp << "*2= " << s2Tmp*2 << "\n";
s2Tmp = s2Tmp*2;
}
#endif
if(d2 & mask)
strat2++;
d2 = d2 & ~mask;
mask = mask >> 1;
}
strat2 += d2;
#ifdef DEBUG_INFO
if (d2 != 0)
s2Ops << s2Tmp << " -1 " << d2 << " times = " << s2Tmp - d2 << "\n";
std::cout << "Strat1: " << strat1 << "\n";
std::cout << s1Ops.str() << "\n";
std::cout << "\n\nStrat2: " << strat2 << "\n";
std::cout << s2Ops.str() << "\n";
#endif
if (strat1 < strat2)
{
return strat1;
}
else
{
std::cout << "Strat2\n";
return strat2;
}
}
int main()
{
int s = 25;
int t = 193;
std::cout << "s = " << s << " t = " << t << "\n";
std::cout << MinMoves(s, t) << std::endl;
}
Short BFS algorithm. It finds the shortest path in graph where every vertex x is connected to x + 1, x - 1 and x * 2; O(n)
#include <bits/stdc++.h>
using namespace std;
const int _MAX_DIS = 2020;
const int _MIN_DIS = 0;
int minMoves(int begin, int end){
queue<int> Q;
int dis[_MAX_DIS];
fill(dis, dis + _MAX_DIS, -1);
dis[begin] = 0;
Q.push(begin);
while(!Q.empty()){
int v = Q.front(); Q.pop();
int tab[] = {v + 1, v - 1, v * 2};
for(int i = 0; i < 3; i++){
int w = tab[i];
if(_MIN_DIS <= w && w <= _MAX_DIS && dis[w] == -1){
Q.push(w);
dis[w] = dis[v] + 1;
}
}
}
return dis[end];
}
int main(){
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cout << minMoves(1, 1000);
return 0;
}

Visual Studio 2017 C++Debug/Release different output

I've implemented a Kolakoski's sequence with a low memory footprint, using the reference from Wikipedia
#include <iostream>
#include <iomanip>
#include <vector>
int IncrementPointer(std::vector<int>& vec, int k)
{
if (vec.size() <= k)
{
vec.push_back(22);
}
if (vec[k] == 11)
{
vec[k] = 1;
return 1;
}
else if (vec[k] == 22)
{
vec[k] = 2;
return 2;
}
else if (vec[k] == 1)
{
vec[k] = IncrementPointer(vec, k + 1) == 1 ? 2 : 22;
return 2;
}
else if (vec[k] == 2)
{
vec[k] = IncrementPointer(vec, k + 1) == 1 ? 1 : 11;
return 1;
}
return 0;
}
int main()
{
long long iteration = 2;
long long nextPowOf10 = 10;
long long numOf1s = 1;
std::vector<int> vec;
std::cout << std::setw(15) << 'n' << std::setw(15) << "#1s" << std::setw(8) << "P(n)\n";
std::cout << std::setw(15) << 1 << std::setw(15) << numOf1s << '\n';
while (iteration++ <= 100'000'000'000'000)
{
int retvalue = IncrementPointer(vec, 0);
if (retvalue == 1)
++numOf1s;
if (iteration % nextPowOf10 == 0)
{
std::cout << std::setw(15) << nextPowOf10 << std::setw(15) << numOf1s << std::setw(8) << vec.size() << '\n';
nextPowOf10 *= 10;
}
}
return 0;
}
Now, the program internally calculates right elements of the sequence in Debug Mode and outputs expected results. So far, so good.
The problem starts in Release mode, vector gets optimized away (how could it be?), and the elements calculated are now wrong.
The expected sequence is [[1 2] 2 1 1 2 1 2 2 etc.], with first two are preset.
and in release mode the elements are [1 2] 2 1 1 1 1 1 2 ... Clearly, something wrong went on. And subsequently the output is unexpected, and the program crashes, with calling to malloc (so it does have somewhere vector reallocated).
What am I doing wrong? Is it simultaneous push_back to vector and update to the element of vector?
I believe a construct like this exhibits undefined behavior:
vec[k] = IncrementPointer(vec, k + 1) == 1 ? 2 : 22;
It is unspecified whether vec[k] or IncrementPointer(vec, ...) gets evaluated first. vec[k] returns a reference to the corresponding element. If IncrementPointer is called later, it may push new elements into vec which in turn may cause it to reallocate, whereupon that reference becomes dangling.
Make it
int val = IncrementPointer(vec, k + 1);
vec[k] = val == 1 ? 2 : 22;

How do we solve the given scenario efficiently?

We are given a maze in which we need to visit as many rooms as possible. The specialty of the maze is that once you enter any room it will only lead you to rooms with a higher tag in the direction you move . B and C decide to move in opposite directions trying their luck to maximize the number of rooms they search .(They can start with any room , need not be the same)
We need to find out the maximum number of rooms that can be searched.
1. Access to any room with a higher tag is allowed, not just adjacent rooms or the next room with a higher tag.
2. Tags are unique.
So given the input:
12 11 10 1 2 3 4 13 6 7 8 5 9
the answer is 12: (1,2,3,4,6,7,8,9) for B and (5,10,11,12) for C.
I thought of solving this using longest increasing sub sequence first from right and then from left.And the count of unique elements in above two sub sequence would be the answer.
But my logic seems to fail,how can this be done?
My program below computes the maximum number of rooms searched. This has time complexity of O(n^3). I modified the DP algorithm for computing the longest increasing sequence available online to solve OP's problem. This also addresses OP's concerns on arrays like {1,4,6,2,5}. I rightly get the max value as 5 for the previous example. So, I used the idea from #BeyelerStudios that we need to compute the longest increasing subsequence from both left to right and from right to left. But, there is a caveat. If we compute the Left to right max sequence, the sequence from right to left should be on the remaining elements. Example:
For the array {1, 4, 6, 2, 5}. If the forward rooms selected are {1, 4, 5 }, then the reverse longest increasing sequence should be computed on the left out elements {6, 2}.
Below is my program:
#include <iostream>
using namespace std;
// compute the max increasing sequence from right to left.
int r2lRooms (int arr[], int n)
{
int dp[n];
int i =0, j = 0;
int max = 0;
for ( i = 0; i < n; i++ ) {
dp[i] = 1;
}
for (i = n-2; i >= 0; i--) {
for ( j = n-1; j > i; j-- ) {
if ( arr[i] > arr[j] && dp[i] < dp[j] + 1) {
dp[i] = dp[j] + 1;
}
}
}
for ( i = 0; i < n; i++ ) {
if ( max < dp[i] ) {
max = dp[i];
}
}
return max;
}
// compute max rooms.
int maxRooms( int arr[], int n )
{
int dp[n], revArray[n];
int i =0, j = 0, k = 0;
int currentMax = 0;
int forwardMax = 0, reverseMax = 0;
for ( i = 0; i < n; i++ ) {
dp[i] = 1;
}
// First case is that except for first elem, all others are in revArray
for (i=1; i < n; i++, k++) {
revArray[k] = arr[i];
}
reverseMax = r2lRooms (revArray, k);
forwardMax = 1;
if (currentMax < (forwardMax + reverseMax)) {
currentMax = forwardMax + reverseMax;
}
cout << "forwardmax revmax and currentmax are: " << forwardMax << " " << reverseMax << " " << currentMax << endl;
cout << endl;
for ( i = 1; i < n; i++ ) {
k = 0;
forwardMax = 1;
reverseMax = 0;
cout << "Forward elems for arr[" << i << "]=" << arr[i] << endl;
for ( j = 0; j < i; j++ ) {
if ( arr[i] > arr[j] && dp[i] < dp[j] + 1) {
dp[i] = dp[j] + 1;
forwardMax = dp[i];
cout << arr[j] << " ";
}
else {
// element was not in DP calculation, so put in revArray.
revArray[k] = arr[j];
k++;
}
}
// copy the remaining elements in revArray.
for ( j = i+1; j < n; j++ ) {
revArray[k] = arr[j];
k++;
}
cout << endl;
reverseMax = r2lRooms (revArray, k);
if (currentMax < (forwardMax + reverseMax)) {
currentMax = forwardMax + reverseMax;
}
cout << "forwardmax revmax and currentmax are: " << forwardMax << " " << reverseMax << " " << currentMax << endl;
cout << endl;
}
cout << " Max rooms searched " << currentMax << endl;
return currentMax;
}
int main (void) {
int arr[] = {12, 11, 10, 1, 2, 3, 4, 13, 6, 7, 8, 5, 9 };
int size = sizeof(arr) / sizeof(int);
cout << maxRooms (arr, size);
}
I think the trick is at the intersection, where B and C might share a value or there's options to go around that (say the sequence is 12 11 10 1 2 3 4 <3 5> 13 6 7 8 9 The extra numbers here adds 1 to the solution, but doesn't change the result for either longest increasing sub-sequences.
So the only problem is the one room in the middle, since on both side the values chosen diverge.
What I would do is this: do the longest subsequence in one direction, figure out a solution (any solution), take out the numbers in the solution and do the longest subsequence in the other direction. This way if there's a way around the crossing room in the middle the second pass will prefer it, unless that's the chosen number is really needed. To check for that do the same thing, but build the first subsequence in the opposite direction and the second one (after removing the solution) in the direction chosen initially.
Complexity remains O(N) but with a slightly higher constant factor.

how to represent a number as a sum of 4 primes?

Here is the problem (Summation of Four Primes) states that :
The input contains one integer number N (N<=10000000) in every line. This is the number you will have to express as a summation of four primes
Sample Input: 24 36 46
Sample Output: 3 11 3 7 3
7 13 13 11 11 17 7
This idea comes to my mind at a first glance
Find all primes below N
Find length of list (.length = 4) with Integer Partition problem (Knapsack)
but complexity is very bad for this algorithm I think. This problem also looks like Goldbach's_conjecture
more. How can I solve this problem?
This problem has a simple trick.
You can express all numbers as 3+2 + "summation of two primes"
or
2 + 2 + "summation of two primes"
depending on parity of the number.
for the "summation of two primes", use Goldbach's Conjecture.
There are around 700 thousand primes below 10 million.
If the number is even reduce 2 x 2 from it and if odd reduce 2 + 3 from it and finding the other two primes is not difficult because of Goldbach conjecture.
You can implement it by the following code it save a lot of time in your program by make to digit as constant 2 & 2 or 2 & 3 :
int isPrime(int x) {
int s = sqrt(x);
for (int i = 2; i <= s; i++) {
if (x % i == 0) {
return 0;
}
}
return 1;
}
void Num(int x, int & a, int & b) {
for (int i = 2; i <= x / 2; i++) {
if (isPrime(i) && isPrime(x - i)) {
a = i;
b = x - i;
return;
}
}
}
int main() {
int n;
while (cin >> n) {
if (n <= 7) {
cout << "Impossible." << endl;
continue;
}
if (n % 2 !=0) {
int a, b;
Num(n -5, a, b);
cout << "2 3 " << a << " " << b << endl;
}
else {
int a, b;
Num(n -4, a, b);
cout << "2 2 " << a << " " << b << endl;
}
}
return 0;
}

Resources