How can I make a program that checks if binary representation of a given integer is periodical with period length m >= 2?
For example:
Binary representation of 10 is periodical
10 base 10 = 1010 base 2, periodical with period length 2
Binary representation of 9 is not periodical
9 base 10 = 1001 base 2
Binary representation of 153 is periodical
153 base 10 = 10011001 base 2, periodical with period length 4
Is there any specific algorithm for doing this?
I am working in C++.
What you can do is rotate the bits and check each time if the numbers are equal. i.e. the rotated one and the one you start with
// it is being assumed the size of int is 4bytes
int num = 153;
int temp = num;
int i = 0;
for (i=0; i<(8*sizeof(int))/2; i++){
temp = ((temp >> 1) & LONG_MAX | temp << 31) // rotate the bits by 1
if (!(temp ^ num)){ // check if the numbers are the same
break;
}
}
if (i<(8*sizeof(int))/2)
std::cout << "Period is" << i << "\n";
else
std::cout << "Not periodic";
The complexity is linear in the number of bits.
KMP is the specific algorithm to find the period of any string, of source including the binary representation of a number, which is just a string. It run in O(n) time.
#include <iostream>
#include <algorithm>
using namespace std;
int calc_period(string s) {
vector<int> pre(s.size());
// this condition is keeped true in the for-loop:
// s[0..pre[i]] is this longest suffix of s[0..i] in s[0..i]'s all prefixes (if pre[i] >= 0)
int k = -1;
pre[0] = -1;
for (int i = 1; i < int(s.size()); ++i) {
while (k >= 0 && s[k + 1] != s[i]) {
k = pre[k];
}
if (s[k + 1] == s[i]) {
++k;
}
pre[i] = k;
}
int l = s.size() - 1 - pre[s.size() - 1];
return s.size() % l == 0 ? s.size() / l : 1;
}
string to_binary(long long x) {
string s;
if (x == 0) {
s = "0";
} else {
while (x) {
s += (x & 1) ? "1" : "0";
x >>= 1;
}
reverse(s.begin(), s.end());
}
return s;
}
int main() {
int x;
cin >> x;
cout << calc_period(to_binary(x)) << endl;
return 0;
}
You can try this code out to see how it works. If you want to learn deeper about KMP, read its wiki page or related text books such as "Introduction to Algorithm".
Related
I want to find the number of numbers between 1 and n that are valid numbers in base two (binary).
1 ≤ n ≤ 10^9
For example, suppose n is equal to 101.
Input: n = 101
In this case, the answer is 5
Output: 1, 10, 11, 100, 101 -> 5
Another example
Input: n = 13
Output: 1, 10, 11 -> 3
Here is my code...
#include <iostream>
using namespace std;
int main()
{
int n, c = 0;
cin >> n;
for (int i = 1; i <= n; ++i)
{
int temp = i;
bool flag = true;
while(temp != 0) {
int rem = temp % 10;
if (rem > 1)
{
flag = false;
break;
}
temp /= 10;
}
if (flag)
{
c++;
}
}
cout << c;
return 0;
}
But I want more speed.
(With only one loop or maybe without any loop)
Thanks in advance!
The highest binary number that will fit in a d-digit number d1 d2 ... dn is
b1 b2 ... bn where
bi = 0 if di = 0, and
bi = 1 otherwise.
A trivial implementation using std::to_string:
int max_binary(int input) {
int res = 0;
auto x = std::to_string(input);
for (char di : x) {
int bi = x == '0' ? 0 : 1;
res = 2 * res + bi;
}
return res;
}
Details:
In each step, if the digit was one, then we add 2 to the power of the number of digits we have.
If the number was greater than 1, then all cases are possible for that number of digits, and we can also count that digit itself and change the answer altogether (-1 is because we do not want to calculate the 0).
#include <iostream>
using namespace std;
int main()
{
long long int n, res = 0, power = 1;
cin >> n;
while(n != 0) {
int rem = n % 10;
if (rem == 1) {
res += power;
} else if (rem > 1) {
res = 2 * power - 1;
}
n /= 10;
power *= 2;
}
cout << res;
return 0;
}
I have an array with x numbers: sets[ ](long numbers) and a char array operations[ ] with x-1 numbers. For each number from sets[ ], its binary form(in 64bits) would be the same as a set of numbers( these numbers being from 0 to 63 ), 1's and 0's representing whether it is inside a subset or not ( 1 2 4 would be 1 1 0 1, since 3 is missing)
ex: decimal 5 --->000...00101 , meaning that this subset will only have those 2 last numbers inside it(#63 and #61)
now,using the chars i get in operations[], i should work with them and the binaries of these numbers as if they were operations on subsets(i hope subset is the right word), these operations being :
U = reunion ---> 101 U 010 = 111
A = intersection ---> 101 A 001 = 001
\ = A - B ---> 1110 - 0011 = 1100
/ = B-A ---> like the previous one
so basically I'd have to read numbers, make them binary, use them as if they were sets and use operations accordingly, then return the result of all these operations on them.
my code :
include <iostream>
using namespace std;
void makeBinaryVector(int vec[64], long xx)
{
// put xx in binary form in array "vec[]"
int k = 63;
long x = xx;
if(xx == 0)
for(int i=0;i<64;i++)
vec[i] = 0;
while(x != 0)
{
vec[k] = x % 2;
x = x / 2;
k--;
}
}
void OperationInA(int A[64], char op, int B[64])
{
int i;
if(op == 'U') //reunion
for(i=0;i<64;i++)
if(B[i] == 1)
A[i] = 1;
if(op == 'A') //intersection
for(i=0;i<64;i++)
{
if((B[i] == 1) && (A[i] == 1))
A[i] = 1;
else
A[i] = 0;
}
if(op == '\\') //A-B
for(i=0;i<64;i++)
{
if( (A[i] == 0 && B[i] == 0) || (A[i] == 0 && B[i] == 1) )
A[i] = 0;
else
if((A[i] == 1) && (B[i] == 1))
A[i] = 0;
else
if((A[i] == 1) && (B[i] == 0))
A[i] = 1;
}
if(op == '/') //B-A
for(i=0;i<64;i++)
{
if(B[i] == 0)
A[i] = 0;
else
if((B[i] == 1) && (A[i] == 0))
A[i] = 1;
else
if((B[i] == 1) && (A[i] == 1))
A[i] = 0;
}
}
unsigned long setOperations(long sets[], char operations[], unsigned int x)
{
unsigned int i = 1; //not 0, since i'll be reading the 1st number separately
unsigned int j = 0;
unsigned int n = x;
int t;
long a = sets[0];
int A[64];
for(t=0;t<64;t++)
A[t] = 0;
makeBinaryVector(A, a); //hold in A the first number, binary, and the results of operations
long b;
int B[64];
for(t=0;t<64;t++) //Hold the next number in B[], in binary form
B[t] = 0;
char op;
while(i < x && j < (x-1) )
{
b = sets[i];
makeBinaryVector(B, b);
op = operations[j];
OperationInA(A, op, B);
i++; j++;
}
//make array A a decimal number
unsigned int base = 1;
long nr = 0;
for(t=63; t>=0; t--)
{
nr = nr + A[t] * base;
base = base * 2;
}
return nr;
}
long sets[100];
char operations[100];
long n,i;
int main()
{
cin>>n;
for(i=0;i<n;i++)
cin>>sets[i];
for(i=0;i<n-1;i++)
cin>>operations[i];
cout<<setOperations(sets,operations,n);
return 0;
}
So everything seems fine, except when im trying this :
sets = {5, 2, 1}
operations = {'U' , '\'}
5 U 2 is 7(111), and 7 \ 1 is 6 (111 - 001 = 110 --> 6)
the result should be 6, however when i Input them like that the result is 4 (??)
however, if i simply input {7,1} and { \ } the result is 6,as it should be. but if i input them like i first mentioned {5,2,1} and {U,} then its gonna output 4.
I can't seem to understand or see what im doing wrong...
You don't have to "convert to binary numbers".
There's no such thing as 'binary numbers'. You can just perform the operations on the variables.
For the reunion, you can use the bitwise OR operator '|', and for the intersection, you can use the bitwise AND operator '&'.
Something like this:
if (op == 'A')
result = a & b;
else if (op == 'U')
result = a | b;
else if (op == '\\')
result = a - b;
else if (op == '/')
result = b - a;
Use bitwise operators on integers as shown in #Hugal31's answer.
Note that integer size is usually 32bit, not 64bit. On a 64bit system you need long long for 64bit integer. Use sizeof operator to check. int is 4 bytes (32bit) and long long is 8 bytes (64bit).
For the purpose of homework etc., your conversion to vector cannot be right. You should test it to see if it outputs the correct result. Otherwise use this:
void makebinary(int vec[32], int x)
{
int bitmask = 1;
for (int i = 31; i >= 0; i--)
{
vec[i] = (x & bitmask) ? 1 : 0;
bitmask <<= 1;
}
}
Note the use of shift operators. To AND the numbers you can do something like the following:
int vx[32];
int vy[32];
makebinary(vx, x);
makebinary(vy, y);
int result = 0;
int j = 1;
for (int i = 31; i >= 0; i--)
{
int n = (vx[i] & vy[i]) ? 1 : 0;
result += n * j;
j <<= 1;
}
This is of course pointless because you can just say int result = X & Y;
I'm posting this although much has already been posted about this question. I didn't want to post as an answer since it's not working. The answer to this post (Finding the rank of the Given string in list of all possible permutations with Duplicates) did not work for me.
So I tried this (which is a compilation of code I've plagiarized and my attempt to deal with repetitions). The non-repeating cases work fine. BOOKKEEPER generates 83863, not the desired 10743.
(The factorial function and letter counter array 'repeats' are working correctly. I didn't post to save space.)
while (pointer != length)
{
if (sortedWordChars[pointer] != wordArray[pointer])
{
// Swap the current character with the one after that
char temp = sortedWordChars[pointer];
sortedWordChars[pointer] = sortedWordChars[next];
sortedWordChars[next] = temp;
next++;
//For each position check how many characters left have duplicates,
//and use the logic that if you need to permute n things and if 'a' things
//are similar the number of permutations is n!/a!
int ct = repeats[(sortedWordChars[pointer]-64)];
// Increment the rank
if (ct>1) { //repeats?
System.out.println("repeating " + (sortedWordChars[pointer]-64));
//In case of repetition of any character use: (n-1)!/(times)!
//e.g. if there is 1 character which is repeating twice,
//x* (n-1)!/2!
int dividend = getFactorialIter(length - pointer - 1);
int divisor = getFactorialIter(ct);
int quo = dividend/divisor;
rank += quo;
} else {
rank += getFactorialIter(length - pointer - 1);
}
} else
{
pointer++;
next = pointer + 1;
}
}
Note: this answer is for 1-based rankings, as specified implicitly by example. Here's some Python that works at least for the two examples provided. The key fact is that suffixperms * ctr[y] // ctr[x] is the number of permutations whose first letter is y of the length-(i + 1) suffix of perm.
from collections import Counter
def rankperm(perm):
rank = 1
suffixperms = 1
ctr = Counter()
for i in range(len(perm)):
x = perm[((len(perm) - 1) - i)]
ctr[x] += 1
for y in ctr:
if (y < x):
rank += ((suffixperms * ctr[y]) // ctr[x])
suffixperms = ((suffixperms * (i + 1)) // ctr[x])
return rank
print(rankperm('QUESTION'))
print(rankperm('BOOKKEEPER'))
Java version:
public static long rankPerm(String perm) {
long rank = 1;
long suffixPermCount = 1;
java.util.Map<Character, Integer> charCounts =
new java.util.HashMap<Character, Integer>();
for (int i = perm.length() - 1; i > -1; i--) {
char x = perm.charAt(i);
int xCount = charCounts.containsKey(x) ? charCounts.get(x) + 1 : 1;
charCounts.put(x, xCount);
for (java.util.Map.Entry<Character, Integer> e : charCounts.entrySet()) {
if (e.getKey() < x) {
rank += suffixPermCount * e.getValue() / xCount;
}
}
suffixPermCount *= perm.length() - i;
suffixPermCount /= xCount;
}
return rank;
}
Unranking permutations:
from collections import Counter
def unrankperm(letters, rank):
ctr = Counter()
permcount = 1
for i in range(len(letters)):
x = letters[i]
ctr[x] += 1
permcount = (permcount * (i + 1)) // ctr[x]
# ctr is the histogram of letters
# permcount is the number of distinct perms of letters
perm = []
for i in range(len(letters)):
for x in sorted(ctr.keys()):
# suffixcount is the number of distinct perms that begin with x
suffixcount = permcount * ctr[x] // (len(letters) - i)
if rank <= suffixcount:
perm.append(x)
permcount = suffixcount
ctr[x] -= 1
if ctr[x] == 0:
del ctr[x]
break
rank -= suffixcount
return ''.join(perm)
If we use mathematics, the complexity will come down and will be able to find rank quicker. This will be particularly helpful for large strings.
(more details can be found here)
Suggest to programmatically define the approach shown here (screenshot attached below) given below)
I would say David post (the accepted answer) is super cool. However, I would like to improve it further for speed. The inner loop is trying to find inverse order pairs, and for each such inverse order, it tries to contribute to the increment of rank. If we use an ordered map structure (binary search tree or BST) in that place, we can simply do an inorder traversal from the first node (left-bottom) until it reaches the current character in the BST, rather than traversal for the whole map(BST). In C++, std::map is a perfect one for BST implementation. The following code reduces the necessary iterations in loop and removes the if check.
long long rankofword(string s)
{
long long rank = 1;
long long suffixPermCount = 1;
map<char, int> m;
int size = s.size();
for (int i = size - 1; i > -1; i--)
{
char x = s[i];
m[x]++;
for (auto it = m.begin(); it != m.find(x); it++)
rank += suffixPermCount * it->second / m[x];
suffixPermCount *= (size - i);
suffixPermCount /= m[x];
}
return rank;
}
#Dvaid Einstat, this was really helpful. It took me a WHILE to figure out what you were doing as I am still learning my first language(C#). I translated it into C# and figured that I'd give that solution as well since this listing helped me so much!
Thanks!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Text.RegularExpressions;
namespace CsharpVersion
{
class Program
{
//Takes in the word and checks to make sure that the word
//is between 1 and 25 charaters inclusive and only
//letters are used
static string readWord(string prompt, int high)
{
Regex rgx = new Regex("^[a-zA-Z]+$");
string word;
string result;
do
{
Console.WriteLine(prompt);
word = Console.ReadLine();
} while (word == "" | word.Length > high | rgx.IsMatch(word) == false);
result = word.ToUpper();
return result;
}
//Creates a sorted dictionary containing distinct letters
//initialized with 0 frequency
static SortedDictionary<char,int> Counter(string word)
{
char[] wordArray = word.ToCharArray();
int len = word.Length;
SortedDictionary<char,int> count = new SortedDictionary<char,int>();
foreach(char c in word)
{
if(count.ContainsKey(c))
{
}
else
{
count.Add(c, 0);
}
}
return count;
}
//Creates a factorial function
static int Factorial(int n)
{
if (n <= 1)
{
return 1;
}
else
{
return n * Factorial(n - 1);
}
}
//Ranks the word input if there are no repeated charaters
//in the word
static Int64 rankWord(char[] wordArray)
{
int n = wordArray.Length;
Int64 rank = 1;
//loops through the array of letters
for (int i = 0; i < n-1; i++)
{
int x=0;
//loops all letters after i and compares them for factorial calculation
for (int j = i+1; j<n ; j++)
{
if (wordArray[i] > wordArray[j])
{
x++;
}
}
rank = rank + x * (Factorial(n - i - 1));
}
return rank;
}
//Ranks the word input if there are repeated charaters
//in the word
static Int64 rankPerm(String word)
{
Int64 rank = 1;
Int64 suffixPermCount = 1;
SortedDictionary<char, int> counter = Counter(word);
for (int i = word.Length - 1; i > -1; i--)
{
char x = Convert.ToChar(word.Substring(i,1));
int xCount;
if(counter[x] != 0)
{
xCount = counter[x] + 1;
}
else
{
xCount = 1;
}
counter[x] = xCount;
foreach (KeyValuePair<char,int> e in counter)
{
if (e.Key < x)
{
rank += suffixPermCount * e.Value / xCount;
}
}
suffixPermCount *= word.Length - i;
suffixPermCount /= xCount;
}
return rank;
}
static void Main(string[] args)
{
Console.WriteLine("Type Exit to end the program.");
string prompt = "Please enter a word using only letters:";
const int MAX_VALUE = 25;
Int64 rank = new Int64();
string theWord;
do
{
theWord = readWord(prompt, MAX_VALUE);
char[] wordLetters = theWord.ToCharArray();
Array.Sort(wordLetters);
bool duplicate = false;
for(int i = 0; i< theWord.Length - 1; i++)
{
if(wordLetters[i] < wordLetters[i+1])
{
duplicate = true;
}
}
if(duplicate)
{
SortedDictionary<char, int> counter = Counter(theWord);
rank = rankPerm(theWord);
Console.WriteLine("\n" + theWord + " = " + rank);
}
else
{
char[] letters = theWord.ToCharArray();
rank = rankWord(letters);
Console.WriteLine("\n" + theWord + " = " + rank);
}
} while (theWord != "EXIT");
Console.WriteLine("\nPress enter to escape..");
Console.Read();
}
}
}
If there are k distinct characters, the i^th character repeated n_i times, then the total number of permutations is given by
(n_1 + n_2 + ..+ n_k)!
------------------------------------------------
n_1! n_2! ... n_k!
which is the multinomial coefficient.
Now we can use this to compute the rank of a given permutation as follows:
Consider the first character(leftmost). say it was the r^th one in the sorted order of characters.
Now if you replace the first character by any of the 1,2,3,..,(r-1)^th character and consider all possible permutations, each of these permutations will precede the given permutation. The total number can be computed using the above formula.
Once you compute the number for the first character, fix the first character, and repeat the same with the second character and so on.
Here's the C++ implementation to your question
#include<iostream>
using namespace std;
int fact(int f) {
if (f == 0) return 1;
if (f <= 2) return f;
return (f * fact(f - 1));
}
int solve(string s,int n) {
int ans = 1;
int arr[26] = {0};
int len = n - 1;
for (int i = 0; i < n; i++) {
s[i] = toupper(s[i]);
arr[s[i] - 'A']++;
}
for(int i = 0; i < n; i++) {
int temp = 0;
int x = 1;
char c = s[i];
for(int j = 0; j < c - 'A'; j++) temp += arr[j];
for (int j = 0; j < 26; j++) x = (x * fact(arr[j]));
arr[c - 'A']--;
ans = ans + (temp * ((fact(len)) / x));
len--;
}
return ans;
}
int main() {
int i,n;
string s;
cin>>s;
n=s.size();
cout << solve(s,n);
return 0;
}
Java version of unrank for a String:
public static String unrankperm(String letters, int rank) {
Map<Character, Integer> charCounts = new java.util.HashMap<>();
int permcount = 1;
for(int i = 0; i < letters.length(); i++) {
char x = letters.charAt(i);
int xCount = charCounts.containsKey(x) ? charCounts.get(x) + 1 : 1;
charCounts.put(x, xCount);
permcount = (permcount * (i + 1)) / xCount;
}
// charCounts is the histogram of letters
// permcount is the number of distinct perms of letters
StringBuilder perm = new StringBuilder();
for(int i = 0; i < letters.length(); i++) {
List<Character> sorted = new ArrayList<>(charCounts.keySet());
Collections.sort(sorted);
for(Character x : sorted) {
// suffixcount is the number of distinct perms that begin with x
Integer frequency = charCounts.get(x);
int suffixcount = permcount * frequency / (letters.length() - i);
if (rank <= suffixcount) {
perm.append(x);
permcount = suffixcount;
if(frequency == 1) {
charCounts.remove(x);
} else {
charCounts.put(x, frequency - 1);
}
break;
}
rank -= suffixcount;
}
}
return perm.toString();
}
See also n-th-permutation-algorithm-for-use-in-brute-force-bin-packaging-parallelization.
Here is the link to the problem:
http://www.spoj.com/problems/GCD/
Consider the decimal representation of a natural number N.
Find the greatest common divisor (GCD) of all numbers that can be obtained by permuting the digits in the given number. Leading zeroes are allowed.
I worked on the following approach :
https://math.stackexchange.com/a/22453
First, if all the digits are the same, there is only one number and that is the GCD. As was pointed out before, if 3 or 9 is a factor of one permutation it will be a factor of them all. Otherwise, imagine swapping just the ones and tens digit when they are different. The GCD of these two has to divide 100a+10b+c−100a+10c+b=9(b−c) where b and c are single digits. For the GCD of all the numbers to have a factor 2, all the digits must be even. For the GCD to have a factor 4, all the digits must be 0, 4, or 8 and for 8 they must be 0 or 8. Similarly for 5 and 7. Finally, the GCD will be 27 if all the digits are 0,3,6, or 9 and 27 divides one permutation and 81 if all the digits are 0 or 9 and 81 divides one permutation. Can you prove the last assertion?
My solution:
http://ideone.com/VMUb6w
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<string>
using namespace std;
int rem(string str, int a){
if (str.empty())
{
return 0;
}
int temp = (str[str.length() - 1] - '0') % a;
int temp2 = 10 % a;
str.erase(str.length() - 1);
int temp3 = (rem(str, a)*temp2) % a;
return (temp3 + temp) % a;
}
int gcdf(int a, int b)
{
return b ? gcdf(b, a%b) : a;
}
int main(){
string str;
while (cin >> str)
{
size_t l = str.length();
vector<int> digit;
int sum = 0;
int frequency[9];
for (int i = 0; i<9; i++)
frequency[i] = 0;
int zero_sum = 0;
for (size_t i = 0; i < l; i++)
{
if (str.at(i) != '0')
{
frequency[str.at(i) - '1']++;
sum += str.at(i) - '0';
}
else
{
zero_sum++;
}
}
for (size_t i = 0; i < 9; i++)
{
if (frequency[i])
{
digit.push_back(i + 1);
}
}
int gcds = 0, gcd = 1;
for (size_t i = 0; i < digit.size(); i++)
{
gcds = gcdf(digit[i], gcds);
}
if (gcdf(3, gcds) == 1)
{
gcd *= gcds;
}
if (gcds == 6)
{
gcd *= 2;
}
if ((rem(str, 81) == 0) && (gcdf(gcds, 3) == 3))
{
gcd *= 81;
}
else
{
if ((rem(str, 27) == 0) && (gcdf(gcds, 3) == 3))
{
gcd *= 27;
}
else
{
if (sum % 9 == 0)
{
gcd *= 9;
}
else
{
if (sum % 3 == 0)
{
gcd *= 3;
}
}
}
}
if((digit.size()==1)&&(zero_sum==0))
cout<<str;
else
cout << gcd << endl;
}
return 0;
}
But it is giving WA.
I cannot seem to find any edge case on where it might be wrong.
Please tell me where am i wrong. Thanks :)
First, if all the digits are the same, there is only one number and that is the GCD.
You don't handle this (first) case
So with your code all of 11, 111, 44 gives wrong answer.
[..] 81 if all the digits are 0 or 9 and 81 divides one permutation.
It seems that your test is wrong for that:
if ((rem(str, 81) == 0) && (gcdf(gcds, 3) == 3))
Did you mean:
if ((rem(str, 81) == 0) && (gcdf(gcds, 9) == 9))
And so
You have for permutation of 3699 inconsistent results:
27 for 3699, 3996, 6939, 6993, 9369, 9693, 9936
81 for 3969, 6399, 9396, 9639, 9963.
My implementation to check (for int number) is:
int my_gcd(std::string str)
{
std::sort(str.begin(), str.end());
std::string first = str;
int gcd = atoi(first.c_str());
while (std::next_permutation(str.begin(), str.end())) {
gcd = gcdf(atoi(str.c_str()), gcd);
}
return gcd;
}
Suppose I am given:
A range of integers iRange (i.e. from 1 up to iRange) and
A desired number of combinations
I want to find the number of all possible combinations and print out all these combinations.
For example:
Given: iRange = 5 and n = 3
Then the number of combinations is iRange! / ((iRange!-n!)*n!) = 5! / (5-3)! * 3! = 10 combinations, and the output is:
123 - 124 - 125 - 134 - 135 - 145 - 234 - 235 - 245 - 345
Another example:
Given: iRange = 4 and n = 2
Then the number of combinations is iRange! / ((iRange!-n!)*n!) = 4! / (4-2)! * 2! = 6 combinations, and the output is:
12 - 13 - 14 - 23 - 24 - 34
My attempt so far is:
#include <iostream>
using namespace std;
int iRange= 0;
int iN=0;
int fact(int n)
{
if ( n<1)
return 1;
else
return fact(n-1)*n;
}
void print_combinations(int n, int iMxM)
{
int iBigSetFact=fact(iMxM);
int iDiffFact=fact(iMxM-n);
int iSmallSetFact=fact(n);
int iNoTotComb = (iBigSetFact/(iDiffFact*iSmallSetFact));
cout<<"The number of possible combinations is: "<<iNoTotComb<<endl;
cout<<" and these combinations are the following: "<<endl;
int i, j, k;
for (i = 0; i < iMxM - 1; i++)
{
for (j = i + 1; j < iMxM ; j++)
{
//for (k = j + 1; k < iMxM; k++)
cout<<i+1<<j+1<<endl;
}
}
}
int main()
{
cout<<"Please give the range (max) within which the combinations are to be found: "<<endl;
cin>>iRange;
cout<<"Please give the desired number of combinations: "<<endl;
cin>>iN;
print_combinations(iN,iRange);
return 0;
}
My problem:
The part of my code related to the printing of the combinations works only for n = 2, iRange = 4 and I can't make it work in general, i.e., for any n and iRange.
Your solution will only ever work for n=2. Think about using an array (combs) with n ints, then the loop will tick up the last item in the array. When that item reaches max update then comb[n-2] item and set the last item to the previous value +1.
Basically working like a clock but you need logic to find what to uptick and what the next minimum value is.
Looks like a good problem for recursion.
Define a function f(prefix, iMin, iMax, n), that prints all combinations of n digits in the range [iMin, iMax] and returns the total number of combinations. For n = 1, it should print every digit from iMin to iMax and return iMax - iMin + 1.
For your iRange = 5 and n = 3 case, you call f("", 1, 5, 3). The output should be 123 - 124 - 125 - 134 - 135 - 145 - 234 - 235 - 245 - 345.
Notice that the first group of outputs are simply 1 prefixed onto the outputs of f("", 2, 5, 2), i.e. f("1", 2, 5, 2), followed by f("2", 3, 5, 2) and f("3", 4, 5, 2). See how you would do that with a loop. Between this, the case for n = 1 above, and traps for bad inputs (best if they print nothing and return 0, it should simplify your loop), you should be able to write f().
I'm stopping short because this looks like a homework assignment. Is this enough to get you started?
EDIT: Just for giggles, I wrote a Python version. Python has an easier time throwing around sets and lists of things and staying legible.
#!/usr/bin/env python
def Combos(items, n):
if n <= 0 or len(items) == 0:
return []
if n == 1:
return [[x] for x in items]
result = []
for k in range(len(items) - n + 1):
for s in Combos(items[k+1:], n - 1):
result.append([items[k]] + s)
return result
comb = Combos([str(x) for x in range(1, 6)], 3)
print len(comb), " - ".join(["".join(c) for c in comb])
Note that Combos() doesn't care about the types of the items in the items list.
Here is your code edited :D :D with a recursive solution:
#include <iostream>
int iRange=0;
int iN=0; //Number of items taken from iRange, for which u want to print out the combinations
int iTotalCombs=0;
int* pTheRange;
int* pTempRange;
int find_factorial(int n)
{
if ( n<1)
return 1;
else
return find_factorial(n-1)*n;
}
//--->Here is another solution:
void print_out_combinations(int *P, int K, int n_i)
{
if (K == 0)
{
for (int j =iN;j>0;j--)
std::cout<<P[j]<<" ";
std::cout<<std::endl;
}
else
for (int i = n_i; i < iRange; i++)
{
P[K] = pTheRange[i];
print_out_combinations(P, K-1, i+1);
}
}
//Here ends the solution...
int main()
{
std::cout<<"Give the set of items -iRange- = ";
std::cin>>iRange;
std::cout<<"Give the items # -iN- of iRange for which the combinations will be created = ";
std::cin>>iN;
pTheRange = new int[iRange];
for (int i = 0;i<iRange;i++)
{
pTheRange[i]=i+1;
}
pTempRange = new int[iN];
iTotalCombs = (find_factorial(iRange)/(find_factorial(iRange-iN)*find_factorial(iN)));
std::cout<<"The number of possible combinations is: "<<iTotalCombs<<std::endl;
std::cout<<"i.e.the combinations of "<<iN<<" elements drawn from a set of size "<<iRange<<" are: "<<std::endl;
print_out_combinations(pTempRange, iN, 0);
return 0;
}
Here's an example of a plain recursive solution. I believe there exists a more optimal implementation if you replace recursion with cycles. It could be your homework :)
#include <stdio.h>
const int iRange = 9;
const int n = 4;
// A more efficient way to calculate binomial coefficient, in my opinion
int Cnm(int n, int m)
{
int i;
int result = 1;
for (i = m + 1; i <= n; ++i)
result *= i;
for (i = n - m; i > 1; --i)
result /= i;
return result;
}
print_digits(int *digits)
{
int i;
for (i = 0; i < n; ++i) {
printf("%d", digits[i]);
}
printf("\n");
}
void plus_one(int *digits, int index)
{
int i;
// Increment current digit
++digits[index];
// If it is the leftmost digit, run to the right, setup all the others
if (index == 0) {
for (i = 1; i < n; ++i)
digits[i] = digits[i-1] + 1;
}
// step back by one digit recursively
else if (digits[index] > iRange) {
plus_one(digits, index - 1);
}
// otherwise run to the right, setting up other digits, and break the recursion once a digit exceeds iRange
else {
for (i = index + 1; i < n; ++i) {
digits[i] = digits[i-1] + 1;
if (digits[i] > iRange) {
plus_one(digits, i - 1);
break;
}
}
}
}
int main()
{
int i;
int digits[n];
for (i = 0; i < n; ++i) {
digits[i] = i + 1;
}
printf("%d\n\n", Cnm(iRange, n));
// *** This loop has been updated ***
while (digits[0] <= iRange - n + 1) {
print_digits(digits);
plus_one(digits, n - 1);
}
return 0;
}
This is my C++ function with different interface (based on sts::set) but performing the same task:
typedef std::set<int> NumbersSet;
typedef std::set<NumbersSet> CombinationsSet;
CombinationsSet MakeCombinations(const NumbersSet& numbers, int count)
{
CombinationsSet result;
if (!count) throw std::exception();
if (count == numbers.size())
{
result.insert(NumbersSet(numbers.begin(), numbers.end()));
return result;
}
// combinations with 1 element
if (!(count - 1) || (numbers.size() <= 1))
{
for (auto number = numbers.begin(); number != numbers.end(); ++number)
{
NumbersSet single_combination;
single_combination.insert(*number);
result.insert(single_combination);
}
return result;
}
// Combinations with (count - 1) without current number
int first_num = *numbers.begin();
NumbersSet truncated_numbers = numbers;
truncated_numbers.erase(first_num);
CombinationsSet subcombinations = MakeCombinations(truncated_numbers, count - 1);
for (auto subcombination = subcombinations.begin(); subcombination != subcombinations.end(); ++subcombination)
{
NumbersSet cmb = *subcombination;
// Add current number
cmb.insert(first_num);
result.insert(cmb);
}
// Combinations with (count) without current number
subcombinations = MakeCombinations(truncated_numbers, count);
result.insert(subcombinations.begin(), subcombinations.end());
return result;
}
I created a next_combination() function similar to next_permutation(), but valid input is required to make it work
//nums should always be in ascending order
vector <int> next_combination(vector<int>nums, int max){
int size = nums.size();
if(nums[size-1]+1<=max){
nums[size-1]++;
return nums;
}else{
if(nums[0] == max - (size -1)){
nums[0] = -1;
return nums;
}
int pos;
int negate = -1;
for(int i = size-2; i>=0; i--){
if(nums[i]+1 <= max + negate){
pos = i;
break;
}
negate --;
}
nums[pos]++;
pos++;
while(pos<size){
nums[pos] = nums[pos-1]+1;
pos++;
}
}
return nums;
}