How can i calculate the Nth combo based only on it's index.
There should be (n+k-1)!/(k!(n-1)!) combinations with repetitions.
with n=2, k=5 you get:
0|{0,0,0,0,0}
1|{0,0,0,0,1}
2|{0,0,0,1,1}
3|{0,0,1,1,1}
4|{0,1,1,1,1}
5|{1,1,1,1,1}
So black_magic_function(3) should produce {0,0,1,1,1}.
This will be going into a GPU shader, so i want each work-group/thread to be able to figure out their subset of permutations without having to store the sequence globally.
with n=3, k=5 you get:
i=0, {0,0,0,0,0}
i=1, {0,0,0,0,1}
i=2, {0,0,0,0,2}
i=3, {0,0,0,1,1}
i=4, {0,0,0,1,2}
i=5, {0,0,0,2,2}
i=6, {0,0,1,1,1}
i=7, {0,0,1,1,2}
i=8, {0,0,1,2,2}
i=9, {0,0,2,2,2}
i=10, {0,1,1,1,1}
i=11, {0,1,1,1,2}
i=12, {0,1,1,2,2}
i=13, {0,1,2,2,2}
i=14, {0,2,2,2,2}
i=15, {1,1,1,1,1}
i=16, {1,1,1,1,2}
i=17, {1,1,1,2,2}
i=18, {1,1,2,2,2}
i=19, {1,2,2,2,2}
i=20, {2,2,2,2,2}
The algorithm for generating it can be seen as MBnext_multicombination at http://www.martinbroadhurst.com/combinatorial-algorithms.html
Update:
So i thought i'd replace the binomial coefficient in pascals triangle with (n+k-1)!/(k!(n-1)!) to see how it looks.
(* Mathematica code to display pascal and other triangle *)
t1 = Table[Binomial[n, k], {n, 0, 8}, {k, 0, n}];
t2 = Table[(n + k - 1)!/(k! (n - 1)!), {n, 0, 8}, {k, 0, n}];
(*display*)
{Row[#, "\t"]} & /# t1 // Grid
{Row[#, "\t"]} & /# t2 // Grid
T1:
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
1 7 21 35 35 21 7 1
1 8 28 56 70 56 28 8 1
T2:
Indeterminate
1 1
1 2 3
1 3 6 10
1 4 10 20 35
1 5 15 35 70 126
1 6 21 56 126 252 462
1 7 28 84 210 462 924 1716
1 8 36 120 330 792 1716 3432 6435
Comparing with the n=3,k=5 console output at the start of this post: the third diagonal {3,6,10,15,21,28,36} gives the index of each roll-over point {0,0,0,1,1} -> {0,0,1,1,1} -> {0,1,1,1,1}, etc. And the diagonal to the left of it seems to show how many values are contained in the previous block (diagonal[2][i] == diagonal[3][i] - diagonal[3][i-1])). And if you read the 5th row of the pyramid horizontally you get the max amount of combinations for increasing values of N in (n+k-1)!/(k!(n-1)!) where K=5.
There is probably a way to use this information to determine the exact combo for an arbitrary index, without enumerating the whole set, but i'm not sure if i need to go that far. The original problem was just to decompose the full combo space into equal subsets, that can be generated locally, and worked on in parallel by the GPU. So the triangle above gives us the starting index of every block, of which the combo can be trivially derived, and all its successive elements incrementally enumerated. It also gives us the block size, and how many total combinations we have. So now it becomes a packing problem of how to fit unevenly sized blocks into groups of equal work load across X amount of threads.
See the example at:
https://en.wikipedia.org/wiki/Combinatorial_number_system#Finding_the_k-combination_for_a_given_number
Just replace the binomial Coefficient with (n+k-1)!/(k!(n-1)!).
Assuming n=3,k=5, let's say we want to calculate the 19th combination (id=19).
id=0, {0,0,0,0,0}
id=1, {0,0,0,0,1}
id=2, {0,0,0,0,2}
...
id=16, {1,1,1,1,2}
id=17, {1,1,1,2,2}
id=18, {1,1,2,2,2}
id=19, {1,2,2,2,2}
id=20, {2,2,2,2,2}
The result we're looking for is {1,2,2,2,2}.
Examining our 'T2' triangle: n=3,k=5 points to 21, being the 5th number (top to bottom) of the third diagonal (left to right).
Indeterminate
1 1
1 2 3
1 3 6 10
1 4 10 20 35
1 5 15 35 70 126
1 6 21 56 126 252 462
1 7 28 84 210 462 924 1716
1 8 36 120 330 792 1716 3432 6435
We need to find the largest number in this row (horizontally, not diagonally) that does not exceed our id=19 value. So moving left from 21 we arrive at 6 (this operation is performed by the largest function below). Since 6 is the 2nd number in this row it corresponds to n==2 (or g[2,5] == 6 from the code below).
Now that we've found the 5th number in the combination, we move up a floor in the pyramid, so k-1=4. We also subtract the 6 we encountered below from id, so id=19-6=13. Repeating the entire process we find 5 (n==2 again) to be the largest number less than 13 in this row.
Next: 13-5=8, Largest is 4 in this row (n==2 yet again).
Next: 8-4=4, Largest is 3 in this row (n==2 one more time).
Next: 4-3=1, Largest is 1 in this row (n==1)
So collecting the indices at each stage we get {1,2,2,2,2}
The following Mathematica code does the job:
g[n_, k_] := (n + k - 1)!/(k! (n - 1)!)
largest[i_, nn_, kk_] := With[
{x = g[nn, kk]},
If[x > i, largest[i, nn-1, kk], {nn,x}]
]
id2combo[id_, n_, 0] := {}
id2combo[id_, n_, k_] := Module[
{val, offset},
{val, offset} = largest[id, n, k];
Append[id2combo[id-offset, n, k-1], val]
]
Update:
The order that the combinations were being generated by MBnext_multicombination wasn't matching id2combo, so i don't think they were lexicographic. The function below generates them in the same order as id2combo and matches the order of mathematica's Sort[]function on a list of lists.
void next_combo(unsigned int *ar, unsigned int n, unsigned int k)
{
unsigned int i, lowest_i;
for (i=lowest_i=0; i < k; ++i)
lowest_i = (ar[i] < ar[lowest_i]) ? i : lowest_i;
++ar[lowest_i];
i = (ar[lowest_i] >= n)
? 0 // 0 -> all combinations have been exhausted, reset to first combination.
: lowest_i+1; // _ -> base incremented. digits to the right of it are now zero.
for (; i<k; ++i)
ar[i] = 0;
}
Here is a combinatorial number system implementation which handles combinations with and without repetition (i.e multiset), and can optionally produce lexicographic ordering.
/// Combinatorial number system encoder/decoder
/// https://en.wikipedia.org/wiki/Combinatorial_number_system
struct CNS(
/// Type for packed representation
P,
/// Type for one position in unpacked representation
U,
/// Number of positions in unpacked representation
size_t N,
/// Cardinality (maximum value plus one) of one position in unpacked representation
U unpackedCard,
/// Produce lexicographic ordering?
bool lexicographic,
/// Are repetitions representable? (multiset support)
bool multiset,
)
{
static:
/// Cardinality (maximum value plus one) of the packed representation
static if (multiset)
enum P packedCard = multisetCoefficient(unpackedCard, N);
else
enum P packedCard = binomialCoefficient(unpackedCard, N);
alias Index = P;
private P summand(U value, Index i)
{
static if (lexicographic)
{
value = cast(U)(unpackedCard-1 - value);
i = cast(Index)(N-1 - i);
}
static if (multiset)
value += i;
return binomialCoefficient(value, i + 1);
}
P pack(U[N] values)
{
P packed = 0;
foreach (Index i, value; values)
{
static if (!multiset)
assert(i == 0 || value > values[i-1]);
else
assert(i == 0 || value >= values[i-1]);
packed += summand(value, i);
}
static if (lexicographic)
packed = packedCard-1 - packed;
return packed;
}
U[N] unpack(P packed)
{
static if (lexicographic)
packed = packedCard-1 - packed;
void unpackOne(Index i, ref U r)
{
bool checkValue(U value, U nextValue)
{
if (summand(nextValue, i) > packed)
{
r = value;
packed -= summand(value, i);
return true;
}
return false;
}
// TODO optimize: (rolling product / binary search / precomputed tables)
// TODO optimize: don't check below N-i
static if (lexicographic)
{
foreach_reverse (U value; 0 .. unpackedCard)
if (checkValue(value, cast(U)(value - 1)))
break;
}
else
{
foreach (U value; 0 .. unpackedCard)
if (checkValue(value, cast(U)(value + 1)))
break;
}
}
U[N] values;
static if (lexicographic)
foreach (Index i, ref r; values)
unpackOne(i, r);
else
foreach_reverse (Index i, ref r; values)
unpackOne(i, r);
return values;
}
}
Full code: https://gist.github.com/CyberShadow/67da819b78c5fd16d266a1a3b4154203
I have done some preliminary analysis on the problem. Before I talk about the inefficient solution I found, let me give you a link to a paper I wrote on how to translate the k-indexes (or combination) to the rank or lexigraphic index to the combinations associated with the binomial coefficient:
http://tablizingthebinomialcoeff.wordpress.com/
I started out the same way in trying to solve this problem. I came up with the following code that uses one loop for each value of k in the formula (n+k-1)!/k!(n-1)! when k = 5. As written, this code will generate all combinations for the case of n choose 5:
private static void GetCombos(int nElements)
{
// This code shows how to generate all the k-indexes or combinations for any number of elements when k = 5.
int k1, k2, k3, k4, k5;
int n = nElements;
int i = 0;
for (k5 = 0; k5 < n; k5++)
{
for (k4 = k5; k4 < n; k4++)
{
for (k3 = k4; k3 < n; k3++)
{
for (k2 = k3; k2 < n; k2++)
{
for (k1 = k2; k1 < n; k1++)
{
Console.WriteLine("i = " + i.ToString() + ", " + k5.ToString() + " " + k4.ToString() +
" " + k3.ToString() + " " + k2.ToString() + " " + k1.ToString() + " ");
i++;
}
}
}
}
}
}
The output from this method is:
i = 0, 0 0 0 0 0
i = 1, 0 0 0 0 1
i = 2, 0 0 0 0 2
i = 3, 0 0 0 1 1
i = 4, 0 0 0 1 2
i = 5, 0 0 0 2 2
i = 6, 0 0 1 1 1
i = 7, 0 0 1 1 2
i = 8, 0 0 1 2 2
i = 9, 0 0 2 2 2
i = 10, 0 1 1 1 1
i = 11, 0 1 1 1 2
i = 12, 0 1 1 2 2
i = 13, 0 1 2 2 2
i = 14, 0 2 2 2 2
i = 15, 1 1 1 1 1
i = 16, 1 1 1 1 2
i = 17, 1 1 1 2 2
i = 18, 1 1 2 2 2
i = 19, 1 2 2 2 2
i = 20, 2 2 2 2 2
This is the same values as you gave in your edited answer. I also have tried it with 4 choose 5 as well, and it looks like it generates the correct combinations as well.
I wrote this in C#, but you should be able to use it with other languages like C/C++, Java, or Python without too many edits.
One idea for a somewhat inefficient solution is to modify GetCombos to accept k as an input as well. Since k is limited to 6, it would then be possible to put in a test for k. So the code to generate all possible combinations for an n choose k case would then look like this:
private static void GetCombos(int k, int nElements)
{
// This code shows how to generate all the k-indexes or combinations for any n choose k, where k <= 6.
//
int k1, k2, k3, k4, k5, k6;
int n = nElements;
int i = 0;
if (k == 6)
{
for (k6 = 0; k6 < n; k6++)
{
for (k5 = 0; k5 < n; k5++)
{
for (k4 = k5; k4 < n; k4++)
{
for (k3 = k4; k3 < n; k3++)
{
for (k2 = k3; k2 < n; k2++)
{
for (k1 = k2; k1 < n; k1++)
{
Console.WriteLine("i = " + i.ToString() + ", " + k5.ToString() + " " + k4.ToString() +
" " + k3.ToString() + " " + k2.ToString() + " " + k1.ToString() + " ");
i++;
}
}
}
}
}
}
}
else if (k == 5)
{
for (k5 = 0; k5 < n; k5++)
{
for (k4 = k5; k4 < n; k4++)
{
for (k3 = k4; k3 < n; k3++)
{
for (k2 = k3; k2 < n; k2++)
{
for (k1 = k2; k1 < n; k1++)
{
Console.WriteLine("i = " + i.ToString() + ", " + k5.ToString() + " " + k4.ToString() +
" " + k3.ToString() + " " + k2.ToString() + " " + k1.ToString() + " ");
i++;
}
}
}
}
}
}
else if (k == 4)
{
// One less loop than k = 5.
}
else if (k == 3)
{
// One less loop than k = 4.
}
else if (k == 2)
{
// One less loop than k = 3.
}
else
{
// k = 1 - error?
}
}
So, we now have a method that will generate all the combinations of interest. But, the problem is to obtain a specific combination from the lexigraphic order or rank of where that combination lies within the set. So, this can accomplished by a simple count and then returning the proper combination when it hits the specified value. So, to accommodate this an extra parameter that represents the rank needs to be added to the method. So, a new function to do this looks like this:
private static int[] GetComboOfRank(int k, int nElements, int Rank)
{
// Gets the combination for the rank using the formula (n+k-1)!/k!(n-1)! where k <= 6.
int k1, k2, k3, k4, k5, k6;
int n = nElements;
int i = 0;
int[] ReturnArray = new int[k];
if (k == 6)
{
for (k6 = 0; k6 < n; k6++)
{
for (k5 = 0; k5 < n; k5++)
{
for (k4 = k5; k4 < n; k4++)
{
for (k3 = k4; k3 < n; k3++)
{
for (k2 = k3; k2 < n; k2++)
{
for (k1 = k2; k1 < n; k1++)
{
if (i == Rank)
{
ReturnArray[0] = k1;
ReturnArray[1] = k2;
ReturnArray[2] = k3;
ReturnArray[3] = k4;
ReturnArray[4] = k5;
ReturnArray[5] = k6;
return ReturnArray;
}
i++;
}
}
}
}
}
}
}
else if (k == 5)
{
for (k5 = 0; k5 < n; k5++)
{
for (k4 = k5; k4 < n; k4++)
{
for (k3 = k4; k3 < n; k3++)
{
for (k2 = k3; k2 < n; k2++)
{
for (k1 = k2; k1 < n; k1++)
{
if (i == Rank)
{
ReturnArray[0] = k1;
ReturnArray[1] = k2;
ReturnArray[2] = k3;
ReturnArray[3] = k4;
ReturnArray[4] = k5;
return ReturnArray;
}
i++;
}
}
}
}
}
}
else if (k == 4)
{
// Same code as in the other cases, but with one less loop than k = 5.
}
else if (k == 3)
{
// Same code as in the other cases, but with one less loop than k = 4.
}
else if (k == 2)
{
// Same code as in the other cases, but with one less loop than k = 3.
}
else
{
// k = 1 - error?
}
// Should not ever get here. If we do - it is some sort of error.
throw ("GetComboOfRank - did not find rank");
}
ReturnArray returns the combination associated with the rank. So, this code should work for you. However, it will be much slower than what could be achieved if a table lookup was done. The problem with 300 choose 6 is that:
300 choose 6 = 305! / (6!(299!) = 305*304*303*302*301*300 / 6! = 1,064,089,721,800
That is probably way too much data to store in memory. So, if you could get n down to 20, through preprocessing then you would be looking at a total of:
20 choose 6 = 25! / (6!(19!)) = 25*24*23*22*21*20 / 6! = 177,100
20 choose 5 = 24! / (5!(19!)) = 24*23*22*21,20 / 5! = 42,504
20 choose 4 = 23! / (4!(19!)) = 23*22*21*20 / 4! = 8,855
20 choose 3 = 22! / (3!(19!)) = 22*21*20 / 3! = 1,540
20 choose 2 = 21! / (2!(19!)) = 22*21 / 2! = 231
=======
230,230
If one byte is used for each value of the combination, then the total number of bytes used to store a table (via a jagged array or perhaps 5 separate tables) in memory could be calculated as:
177,100 * 6 = 1,062,600
42,504 * 5 = 212,520
8,855 * 4 = 35,420
1,540 * 3 = 4,620
231 * 2 = 462
=========
1,315,622
It depends on the target machine and how much memory is available, but 1,315,622 bytes is not that much memory when many machines today have gigabytes of memory available.
Related
This is my code. 1<=i<=j<=n j-i<=a 1<=n<=1000000 0<=a<=1000000
#include <iostream>
using namespace std;
int main(){
int n, a, r = 0;
cin>>n>>a;
for(int i = 1; i <= n; i++){
int j = i;
for(j; j <= n; j++){
if(j-i<=a){
r++;
}
}
}
cout<<r;
}
Instead of loops, I changed it to a simple check of variables, which greatly accelerated the code. there is no need to calculate thousands of options.
My final, optimized code is:
#include <iostream>
using namespace std;
int main(){
unsigned long long n, a, r = 0;
cin>>n>>a;
if(a==0){
r = n;
}
if(n<=a){
r = (n*(n+1))/2;
}
if(n>a){
r += (n-a)*(a+1) + (a*(a+1))/2;
}
cout<<r;
}
After accounting for both positive numbers, negative numbers, and zeros, your double-nested for-loop can be simplified into this:
if (n < 1)
{
r = 0;
}
else if (a == 0)
{
r = n;
}
else if (a < 0)
{
r = 0;
}
else if (n <= a)
{
r = (n * (n + 1)) / 2;
}
else
{
r = (n-a)*(a + 1) + (a * (a + 1)) / 2;
}
Recall that summing a sequence of digits from 1..N is:
N*(N+1)
-------
2
If n <= a (positive numbers), r is incremented n times in the inner loop on the first iteration of the outer loop. Then n-1 times, then n-2 times... all the way down to 1.
For cases where n > a, then there are n-a summations of a+1 followed by a decrementing summation from a down to 1
This strikes me as something to speed up by doing a bit of math, not by massaging the code.
Basically, we can think of the loops as defining a square matrix of the values of i and j. So let's assume n = 9, and a = 3. I'll draw in a + for each place we increment r, a blank for the values we don't generate, and a 0 for the places we generate values, but don't increment r.
i\j 1 2 3 4 5 6 7 8 9
1 + + + + 0 0 0 0 0
2 + + + + 0 0 0 0
3 + + + + 0 0 0
4 + + + + 0 0
5 + + + + 0
6 + + + +
7 + + +
8 + +
9 +
So, ignoring the last a rows (i.e., for the first n-a rows), in each row we have a band a + 1 elements wide where we do an increment. Then at the end, we have a triangle, where we're basically summing a + a-1 + a-2 ... 0.
So, the first piece is (a+1) * (n-a) and the second piece is a * (a+1) / 2. Add those together, and we get the final answer.
Seems like
for(j; j <= n; j++){
if(j-i<=a){
r++;
}
}
could be replaced by
r += f(i,n,a);
Where f() is some simple expression involving those 3 values, probably including the equivalent of min(..,..)
If you want to speed up your code, instead of just tuning your algorithm, you can also try to use some parallel api.
Parallel computing api such as OpenMP enables you take advantage of your cpu resources.
If you uses OpenMP, you can try to use it to parallel your loop.
I want to compute the number of times fib(n) is called FOR EACH n. I have written the code as below:
#include <stdio.h>
#define N 10
int count[N + 1]; // count[n] keeps track of the number of times each fib(n) is called
int fib(int n) {
count[n]++;
if(n <= 1)
return n;
else
return fib(n - 1) + fib(n - 2);
}
int main() {
for(int i = 0; i <= N; i++) {
count[i] = 0; // initialize count to 0
}
fib(N);
// print values of count[]
for(int i = 0; i <= N; i++) {
printf("count[%d] = %d", i, count[i]);
}
}
I have tried printing the array count[] to get the result, where the result is resembles the fibonacci numbers except for count[0]:
count[0] = 34 count[1] = 55 count[2] = 34 count[3] = 21 count[4] = 13
count[5] = 8 count[6] = 5 count[7] = 3 count[8] = 2 count[9] = 1
count[10] = 1
Is there a way to mathematically show this result, maybe a recursive formula? Also, why doesn't count[0], or rather fib(0), doesn't continue the fibonacci sequence? Thanks.
Because count[1] is going to be called for each count[2] + count[3] but count[0] is only going to be called for count[2]...count[1] doesn't contribute because it's a terminus.
As for mathematical formula:
if n == 0: fib(N - 1)
else: fib(N-(n-1))
As for calculation
call(n)=call(n-1)+call(n-2)+1
call(1)=1
call(0)=1
Hope this make things clear.
n | calls
---+--------
0 | 1
1 | 1
2 | 3
3 | 5 f(3)= f(2)[= f(1)+ f(0)]+ f(1)
5 | 9
.
fib(n) 2*fib(n)-1
Can anybody find any potentially more efficient algorithms for accomplishing the following task?:
For any given permutation of the integers 0 thru 7, return the index which describes the permutation lexicographically (indexed from 0, not 1).
For example,
The array 0 1 2 3 4 5 6 7 should return an index of 0.
The array 0 1 2 3 4 5 7 6 should return an index of 1.
The array 0 1 2 3 4 6 5 7 should return an index of 2.
The array 1 0 2 3 4 5 6 7 should return an index of 5039 (that's 7!-1 or factorial(7)-1).
The array 7 6 5 4 3 2 1 0 should return an index of 40319 (that's 8!-1). This is the maximum possible return value.
My current code looks like this:
int lexic_ix(int* A){
int value = 0;
for(int i=0 ; i<7 ; i++){
int x = A[i];
for(int j=0 ; j<i ; j++)
if(A[j]<A[i]) x--;
value += x*factorial(7-i); // actual unrolled version doesn't have a function call
}
return value;
}
I'm wondering if there's any way I can reduce the number of operations by removing that inner loop, or if I can reduce conditional branching in any way (other than unrolling - my current code is actually an unrolled version of the above), or if there are any clever bitwise hacks or filthy C tricks to help.
I already tried replacing
if(A[j]<A[i]) x--;
with
x -= (A[j]<A[i]);
and I also tried
x = A[j]<A[i] ? x-1 : x;
Both replacements actually led to worse performance.
And before anyone says it - YES this is a huge performance bottleneck: currently about 61% of the program's runtime is spent in this function, and NO, I don't want to have a table of precomputed values.
Aside from those, any suggestions are welcome.
Don't know if this helps but here's an other solution :
int lexic_ix(int* A, int n){ //n = last index = number of digits - 1
int value = 0;
int x = 0;
for(int i=0 ; i<n ; i++){
int diff = (A[i] - x); //pb1
if(diff > 0)
{
for(int j=0 ; j<i ; j++)//pb2
{
if(A[j]<A[i] && A[j] > x)
{
if(A[j]==x+1)
{
x++;
}
diff--;
}
}
value += diff;
}
else
{
x++;
}
value *= n - i;
}
return value;
}
I couldn't get rid of the inner loop, so complexity is o(n log(n)) in worst case, but o(n) in best case, versus your solution which is o(n log(n)) in all cases.
Alternatively, you can replace the inner loop by the following to remove some worst cases at the expense of another verification in the inner loop :
int j=0;
while(diff>1 && j<i)
{
if(A[j]<A[i])
{
if(A[j]==x+1)
{
x++;
}
diff--;
}
j++;
}
Explanation :
(or rather "How I ended with that code", I think it is not that different from yours but it can make you have ideas, maybe)
(for less confusion I used characters instead and digit and only four characters)
abcd 0 = ((0 * 3 + 0) * 2 + 0) * 1 + 0
abdc 1 = ((0 * 3 + 0) * 2 + 1) * 1 + 0
acbd 2 = ((0 * 3 + 1) * 2 + 0) * 1 + 0
acdb 3 = ((0 * 3 + 1) * 2 + 1) * 1 + 0
adbc 4 = ((0 * 3 + 2) * 2 + 0) * 1 + 0
adcb 5 = ((0 * 3 + 2) * 2 + 1) * 1 + 0 //pb1
bacd 6 = ((1 * 3 + 0) * 2 + 0) * 1 + 0
badc 7 = ((1 * 3 + 0) * 2 + 1) * 1 + 0
bcad 8 = ((1 * 3 + 1) * 2 + 0) * 1 + 0 //First reflexion
bcda 9 = ((1 * 3 + 1) * 2 + 1) * 1 + 0
bdac 10 = ((1 * 3 + 2) * 2 + 0) * 1 + 0
bdca 11 = ((1 * 3 + 2) * 2 + 1) * 1 + 0
cabd 12 = ((2 * 3 + 0) * 2 + 0) * 1 + 0
cadb 13 = ((2 * 3 + 0) * 2 + 1) * 1 + 0
cbad 14 = ((2 * 3 + 1) * 2 + 0) * 1 + 0
cbda 15 = ((2 * 3 + 1) * 2 + 1) * 1 + 0 //pb2
cdab 16 = ((2 * 3 + 2) * 2 + 0) * 1 + 0
cdba 17 = ((2 * 3 + 2) * 2 + 1) * 1 + 0
[...]
dcba 23 = ((3 * 3 + 2) * 2 + 1) * 1 + 0
First "reflexion" :
An entropy point of view. abcd have the fewest "entropy". If a character is in a place it "shouldn't" be, it creates entropy, and the earlier the entropy is the greatest it becomes.
For bcad for example, lexicographic index is 8 = ((1 * 3 + 1) * 2 + 0) * 1 + 0 and can be calculated that way :
value = 0;
value += max(b - a, 0); // = 1; (a "should be" in the first place [to create the less possible entropy] but instead it is b)
value *= 3 - 0; //last index - current index
value += max(c - b, 0); // = 1; (b "should be" in the second place but instead it is c)
value *= 3 - 1;
value += max(a - c, 0); // = 0; (a "should have been" put earlier, so it does not create entropy to put it there)
value *= 3 - 2;
value += max(d - d, 0); // = 0;
Note that the last operation will always do nothing, that's why "i
First problem (pb1) :
For adcb, for example, the first logic doesn't work (it leads to an lexicographic index of ((0* 3+ 2) * 2+ 0) * 1 = 4) because c-d = 0 but it creates entropy to put c before b. I added x because of that, it represents the first digit/character that isn't placed yet. With x, diff cannot be negative.
For adcb, lexicographic index is 5 = ((0 * 3 + 2) * 2 + 1) * 1 + 0 and can be calculated that way :
value = 0; x=0;
diff = a - a; // = 0; (a is in the right place)
diff == 0 => x++; //x=b now and we don't modify value
value *= 3 - 0; //last index - current index
diff = d - b; // = 2; (b "should be" there (it's x) but instead it is d)
diff > 0 => value += diff; //we add diff to value and we don't modify x
diff = c - b; // = 1; (b "should be" there but instead it is c) This is where it differs from the first reflexion
diff > 0 => value += diff;
value *= 3 - 2;
Second problem (pb2) :
For cbda, for example, lexicographic index is 15 = ((2 * 3 + 1) * 2 + 1) * 1 + 0, but the first reflexion gives : ((2 * 3 + 0) * 2 + 1) * 1 + 0 = 13 and the solution to pb1 gives ((2 * 3 + 1) * 2 + 3) * 1 + 0 = 17. The solution to pb1 doesn't work because the two last characters to place are d and a, so d - a "means" 1 instead of 3. I had to count the characters placed before that comes before the character in place, but after x, so I had to add an inner loop.
Putting it all together :
I then realised that pb1 was just a particular case of pb2, and that if you remove x, and you simply take diff = A[i], we end up with the unnested version of your solution (with factorial calculated little by little, and my diff corresponding to your x).
So, basically, my "contribution" (I think) is to add a variable, x, which can avoid doing the inner loop when diff equals 0 or 1, at the expense of checking if you have to increment x and doing it if so.
I also checked if you have to increment x in the inner loop (if(A[j]==x+1)) because if you take for example badce, x will be b at the end because a comes after b, and you will enter the inner loop one more time, encountering c. If you check x in the inner loop, when you encounter d you have no choice but doing the inner loop, but x will update to c, and when you encounter c you will not enter the inner loop. You can remove this check without breaking the program
With the alternative version and the check in the inner loop it makes 4 different versions. The alternative one with the check is the one in which you enter the less the inner loop, so in terms of "theoretical complexity" it is the best, but in terms of performance/number of operations, I don't know.
Hope all of this helps (since the question is rather old, and I didn't read all the answers in details). If not, I still had fun doing it. Sorry for the long post. Also I'm new on Stack Overflow (as a member), and not a native speaker, so please be nice, and don't hesitate to let me know if I did something wrong.
Linear traversal of memory already in cache really doesn't take much times at all. Don't worry about it. You won't be traversing enough distance before factorial() overflows.
Move the 8 out as a parameter.
int factorial ( int input )
{
return input ? input * factorial (input - 1) : 1;
}
int lexic_ix ( int* arr, int N )
{
int output = 0;
int fact = factorial (N);
for ( int i = 0; i < N - 1; i++ )
{
int order = arr [ i ];
for ( int j = 0; j < i; j++ )
order -= arr [ j ] < arr [ i ];
output += order * (fact /= N - i);
}
return output;
}
int main()
{
int arr [ ] = { 11, 10, 9, 8, 7 , 6 , 5 , 4 , 3 , 2 , 1 , 0 };
const int length = 12;
for ( int i = 0; i < length; ++i )
std::cout << lexic_ix ( arr + i, length - i ) << std::endl;
}
Say, for a M-digit sequence permutation, from your code, you can get the lexicographic SN formula which is something like: Am-1*(m-1)! + Am-2*(m-2)! + ... + A0*(0)! , where Aj range from 0 to j. You can calculate SN from A0*(0)!, then A1*(1)!, ..., then Am-1 * (m-1)!, and add these together(suppose your integer type does not overflow), so you do not need calculate factorials recursively and repeatedly. The SN number is a range from 0 to M!-1 (because Sum(n*n!, n in 0,1, ...n) = (n+1)!-1)
If you are not calculating factorials recursively, I cannot think of anything that could make any big improvement.
Sorry for posting the code a little bit late, I just did some research, and find this:
http://swortham.blogspot.com.au/2011/10/how-much-faster-is-multiplication-than.html
according to this author, integer multiplication can be 40 times faster than integer division. floating numbers are not so dramatic though, but here is pure integer.
int lexic_ix ( int arr[], int N )
{
// if this function will be called repeatedly, consider pass in this pointer as parameter
std::unique_ptr<int[]> coeff_arr = std::make_unique<int[]>(N);
for ( int i = 0; i < N - 1; i++ )
{
int order = arr [ i ];
for ( int j = 0; j < i; j++ )
order -= arr [ j ] < arr [ i ];
coeff_arr[i] = order; // save this into coeff_arr for later multiplication
}
//
// There are 2 points about the following code:
// 1). most modern processors have built-in multiplier, \
// and multiplication is much faster than division
// 2). In your code, you are only the maximum permutation serial number,
// if you put in a random sequence, say, when length is 10, you put in
// a random sequence, say, {3, 7, 2, 9, 0, 1, 5, 8, 4, 6}; if you look into
// the coeff_arr[] in debugger, you can see that coeff_arr[] is:
// {3, 6, 2, 6, 0, 0, 1, 2, 0, 0}, the last number will always be zero anyway.
// so, you will have good chance to reduce many multiplications.
// I did not do any performance profiling, you could have a go, and it will be
// much appreciated if you could give some feedback about the result.
//
long fac = 1;
long sn = 0;
for (int i = 1; i < N; ++i) // start from 1, because coeff_arr[N-1] is always 0
{
fac *= i;
if (coeff_arr[N - 1 - i])
sn += coeff_arr[N - 1 - i] * fac;
}
return sn;
}
int main()
{
int arr [ ] = { 3, 7, 2, 9, 0, 1, 5, 8, 4, 6 }; // try this and check coeff_arr
const int length = 10;
std::cout << lexic_ix(arr, length ) << std::endl;
return 0;
}
This is the whole profiling code, I only run the test in Linux, code was compiled using G++8.4, with '-std=c++11 -O3' compiler options. To be fair, I slightly rewrote your code, pre-calculate the N! and pass it into the function, but it seems this does not help much.
The performance profiling for N = 9 (362,880 permutations) is:
Time durations are: 34, 30, 25 milliseconds
Time durations are: 34, 30, 25 milliseconds
Time durations are: 33, 30, 25 milliseconds
The performance profiling for N=10 (3,628,800 permutations) is:
Time durations are: 345, 335, 275 milliseconds
Time durations are: 348, 334, 275 milliseconds
Time durations are: 345, 335, 275 milliseconds
The first number is your original function, the second is the function re-written that gets N! passed in, the last number is my result. The permutation generation function is very primitive and runs slowly, but as long as it generates all permutations as testing dataset, that is alright. By the way, these tests are run on a Quad-Core 3.1Ghz, 4GBytes desktop running Ubuntu 14.04.
EDIT: I forgot a factor that the first function may need to expand the lexi_numbers vector, so I put an empty call before timing. After this, the times are 333, 334, 275.
EDIT: Another factor that could influence the performance, I am using long integer in my code, if I change those 2 'long' to 2 'int', the running time will become: 334, 333, 264.
#include <iostream>
#include <vector>
#include <chrono>
using namespace std::chrono;
int factorial(int input)
{
return input ? input * factorial(input - 1) : 1;
}
int lexic_ix(int* arr, int N)
{
int output = 0;
int fact = factorial(N);
for (int i = 0; i < N - 1; i++)
{
int order = arr[i];
for (int j = 0; j < i; j++)
order -= arr[j] < arr[i];
output += order * (fact /= N - i);
}
return output;
}
int lexic_ix1(int* arr, int N, int N_fac)
{
int output = 0;
int fact = N_fac;
for (int i = 0; i < N - 1; i++)
{
int order = arr[i];
for (int j = 0; j < i; j++)
order -= arr[j] < arr[i];
output += order * (fact /= N - i);
}
return output;
}
int lexic_ix2( int arr[], int N , int coeff_arr[])
{
for ( int i = 0; i < N - 1; i++ )
{
int order = arr [ i ];
for ( int j = 0; j < i; j++ )
order -= arr [ j ] < arr [ i ];
coeff_arr[i] = order;
}
long fac = 1;
long sn = 0;
for (int i = 1; i < N; ++i)
{
fac *= i;
if (coeff_arr[N - 1 - i])
sn += coeff_arr[N - 1 - i] * fac;
}
return sn;
}
std::vector<std::vector<int>> gen_permutation(const std::vector<int>& permu_base)
{
if (permu_base.size() == 1)
return std::vector<std::vector<int>>(1, std::vector<int>(1, permu_base[0]));
std::vector<std::vector<int>> results;
for (int i = 0; i < permu_base.size(); ++i)
{
int cur_int = permu_base[i];
std::vector<int> cur_subseq = permu_base;
cur_subseq.erase(cur_subseq.begin() + i);
std::vector<std::vector<int>> temp = gen_permutation(cur_subseq);
for (auto x : temp)
{
x.insert(x.begin(), cur_int);
results.push_back(x);
}
}
return results;
}
int main()
{
#define N 10
std::vector<int> arr;
int buff_arr[N];
const int length = N;
int N_fac = factorial(N);
for(int i=0; i<N; ++i)
arr.push_back(N-i-1); // for N=10, arr is {9, 8, 7, 6, 5, 4, 3, 2, 1, 0}
std::vector<std::vector<int>> all_permus = gen_permutation(arr);
std::vector<int> lexi_numbers;
// This call is not timed, only to expand the lexi_numbers vector
for (auto x : all_permus)
lexi_numbers.push_back(lexic_ix2(&x[0], length, buff_arr));
lexi_numbers.clear();
auto t0 = high_resolution_clock::now();
for (auto x : all_permus)
lexi_numbers.push_back(lexic_ix(&x[0], length));
auto t1 = high_resolution_clock::now();
lexi_numbers.clear();
auto t2 = high_resolution_clock::now();
for (auto x : all_permus)
lexi_numbers.push_back(lexic_ix1(&x[0], length, N_fac));
auto t3 = high_resolution_clock::now();
lexi_numbers.clear();
auto t4 = high_resolution_clock::now();
for (auto x : all_permus)
lexi_numbers.push_back(lexic_ix2(&x[0], length, buff_arr));
auto t5 = high_resolution_clock::now();
std::cout << std::endl << "Time durations are: " << duration_cast<milliseconds> \
(t1 -t0).count() << ", " << duration_cast<milliseconds>(t3 - t2).count() << ", " \
<< duration_cast<milliseconds>(t5 - t4).count() <<" milliseconds" << std::endl;
return 0;
}
Well, I have to write a program to find the NEAREST number of given number N which has exactly "K" 7s.
For example, if input is:
N K
1773 3
Output:
1777
Oh, one more thing is that N can be 100 000 000 000 000 maximum, will long long be enough to handle this?
My code so far which is not working :(
#include <iostream>
using namespace std;
int main()
{
unsigned long long a, i;
int b, num=0, dig, tmp;
cin>>a>>b;
i=a+1;
do
{
num=0;
tmp=i;
while (tmp>0)
{
dig=tmp%10;
tmp=tmp/10;
if (dig==7)
num++;
}
i++;
}
while(num<b);
cout<<i-1;
return 0;
}
Your problem is not a programming problem but a math problem.
Let m = 1+E(log10(N)), ie the number of digits in the decimal writing of N (it will be probably faster to compute it by counting digits than using a logarithm).
Let mK be the number of 7 in N.
Let N' be the output number.
I see 4 cases:
K >= m : then N' = 7..7 (K digits).
K == mK : then N' = N.
K > mK and K < m : then you replace all non-7 digits with 7, starting from the least significant digits. Ex: N = 1 357 975 , K = 4 => N' = 1 357 777. Warning : there is a special case, if you have a 8, ex: N = 80, N' = 79. You can do this case by using a common prefix, and then generating an all 7 suffix (special case: remove one more from the prefix and add 7 9 7 7 ... 7). See special case in the code.
K < mK : there are two possible numbers.
Lets decompose N: N = a1 a2 ... ap 7 b1 b2 ... bq, where
a1 ... ap are p numbers in [0..9] and
b1 ... bq are q numbers in [0..9] \ {7}
Let A = a1 ... ap 6 9 ... 9 and B = a1 ... ap 8 0 ... 0 (q digits after the 6or the 8). Then, N' = closestToN(A,B). If both numbers are equally close, the choice is up to you.
Sorry for the bad math formatting.
The code can now be more easy to write. Here is my implementation:
#include <iostream>
unsigned long long getClosestWith7(unsigned long long n, unsigned int k)
{
// Count number of digits
unsigned long long tmp = n;
unsigned int m = 0, mK = 0;
while(tmp > 0)
{
if(tmp % 10 == 7) mK++;
tmp /= 10;
m++;
}
// Distinct cases
if(k == mK && n != 0)
return n;
else if(k >= m || n == 0) // implicit: k != mK
{
unsigned long long r = 0;
while(k > 0)
{
r = 10 * r + 7;
k--;
}
return r;
}
else if(k > mK) // implicit: k != mK, k < m
{
unsigned long long r = n;
unsigned long long s = 0;
m = 0;
while(mK < k)
{
if(r % 10 != 7) mK++;
r /= 10;
m++;
}
if(r % 10 == 8) // special case
s = 79 + 100 * (r / 10);
while(m > 0)
{
r = 10 * r + 7;
if(s != 0 && m > 1) // special case
s = 10 * s + 7;
m--;
}
return (r < n && n - r < n - s) || (r >= n && r - n < n - s) ? r : s;
}
else // implicit : k < mK
{
// Generate a and b
unsigned long long a = n;
unsigned long long b = 0;
m = 0;
while(mK > k)
{
if(a % 10 == 7) mK--;
a /= 10;
m++;
}
b = 10 * a + 8;
a = 10 * a + 6;
m--;
while(m > 0)
{
a = 10 * a + 9;
b = 10 * b + 0;
m--;
}
// Compare (return lowest if equal)
return n - a <= b - n ? a : b;
}
}
#define CLOSEST7( N , K ) \
std::cout << "N = " << N << ", K = " << K << " => N' = " << getClosestWith7(N,K) << "\n"
int main()
{
CLOSEST7(1773,3);
CLOSEST7(83,1);
CLOSEST7(17273,3);
CLOSEST7(1273679750,6);
CLOSEST7(1773,1);
CLOSEST7(83,5);
CLOSEST7(0,2);
CLOSEST7(0,0);
}
For your question about long long: it depends on the compiler. Often, the size of this type is 64 bits, so you can store number from 0 to 2^64 - 1 (unsigned), which is 18 446 744 073 709 551 615, so it should be ok for your data range on most implementations.
Some problems:
ans=i records some i after you've divided it a few times, you need to record the original i
You only loop in 1 direction, you need to check in both directions at the same time
Looping through all numbers is fundamentally too slow
If the number is 100 000 000 000 000 and k = 14, you'd need to check 22 222 222 222 223 (100 000 000 000 000-77 777 777 777 777) numbers, which is not viable
Side note - the maximum for long long is 9223372036854775807.
Here is some pseudo-code which should work:
num = number of 7s in input
if (num == k)
print input
if (num < k)
a = input with (k-num) non-7 digits from least significant digit set to 7
let x = last position set
b = substring(input, 1, position)
c = b + 1
d = b - 1
ba = concat(b, substring(a, position, end))
ca = concat(c, substring(a, position, end))
da = concat(d, substring(a, position, end))
if (abs(input - ba) <= abs(input - ca) &&
abs(input - ba) <= abs(input - da))
print b
else
if (abs(input - ca) <= abs(input - ba) &&
abs(input - ca) <= abs(input - da))
print c
else
print d
if (num > k)
x = (k-num)th 7 from least significant digit
a = input with x set to 6 and all less significant digits to 9
b = input with x set to 8 and all less significant digits to 0
if (input - a > b - input)
print b
else
print a
How about this algorithm?
Convert the number into a string.
Count the number of 7s in it.
If it has less 7s than K, change the numbers from the right-most to left into 7s one-by-one until K is reached, then go to step 5.
If it has more 7s than K, change the numbers from the right-most to left into 6s one-by-one only if they are 7, until K is reached, then go to step 5.
Convert it back into an integer.
long long is usable according to Dukeling's answer.
I have a string whose size can be as large as "10,000". I have to count those SUBSEQUENCES which are divisible by 9.
SUBSEQUENCE: A subsequence is an arrangement in which the order of characters of given string is maintained. For ex: if given string is 10292 then some of its subsequences are 1, 102, 10, 19, 12, 12(12 is twice as 2 comes twice), 129, 029, 09, 092, etc. Some numbers which are not subsequences of given string are: 201(2 and 0 can't come before 1), 921, 0291, etc.
I have tried to generate all subsequences(powerset) of given string using bit shifting and checking each string if it is divisible by 9. But this works fine as long as length of string is <=10. After that, I don't get proper subsequences(some subsequences are displayed negative numbers).
Below is my code:
scanf("%s", &str); //input string
int n=strlen(str); //find length of string
//loop to generate subsequences
for(i=1;i<(1<<n);++i){
string subseq;
for(j=0;j<n;++j){
if(i&(1<<j)){
subseq+=str[j]; // generate subsequence
}
}
//convert generated subseq to int; number is 'long' tpye
number=atol(subseq.c_str());printf("%ld\n", number);
//ignore 0 and check if number divisible by 9
if(number!=0&&number%9==0)count++;
}
printf("%ld\n", count);
Since a number is divisible by nine if and only if the sum of its digits is divisible by nine, you can get away with this problem with a O(n) recursive algorithm.
The idea is the following: at each step, split in two the subsequence and determine (recursively) how many sequences have the sum of its digits be i % 9, where i ranges from 0 to 8. Then, you build up this very same table for the whole range by "merging" the two tables in O(1) in the following way. Let's say L is the table for the left split and R for the right one and you need to build the table F for the whole range.
Then you have:
for (i = 0; i < 9; i++) {
F[i] = L[i] + R[i];
for (j = 0; j < 9; j++) {
if (j <= i)
F[i] += L[j] * R[i - j]
else
F[i] += L[j] * R[9 + i - j]
}
}
The base case for a subsequence of only one digit d is obvious: just set F[d % 9] = 1 and all the other entries to zero.
A full C++11 implementation:
#include <iostream>
#include <array>
#include <tuple>
#include <string>
typedef std::array<unsigned int, 9> table;
using std::tuple;
using std::string;
table count(string::iterator beg, string::iterator end)
{
table F;
std::fill(F.begin(), F.end(), 0);
if (beg == end)
return F;
if (beg + 1 == end) {
F[(*beg - '0') % 9] = 1;
return F;
}
size_t distance = std::distance(beg, end);
string::iterator mid = beg + (distance / 2);
table L = count(beg, mid);
table R = count(mid, end);
for (unsigned int i = 0; i < 9; i++) {
F[i] = L[i] + R[i];
for(unsigned int j = 0; j < 9; j++) {
if (j <= i)
F[i] += L[j] * R[i - j];
else
F[i] += L[j] * R[9 + i - j];
}
}
return F;
}
table count(std::string s)
{
return count(s.begin(), s.end());
}
int main(void)
{
using std::cout;
using std::endl;
cout << count("1234")[0] << endl;
cout << count("12349")[0] << endl;
cout << count("9999")[0] << endl;
}
I had an idea!
Since you only have to count the substrings, you don't care what they actually are. So instead, you can just store counts of their possible sums.
Then, what if you had a function that could combine the count tables of two substring sets, and give you the counts of their combinations?
And since I know that was a horrible explanation, I'll give an example. Say you're given the number:
2493
Split it in half and keep splitting until you get individual digits:
2493
/ \
24 93
/\ /\
2 4 9 3
What can 2 sum to? Easy: 2. And 4 can only sum to 4. You can build tables of how many substrings sum to each value (mod 9):
0 1 2 3 4 5 6 7 8
2: 0 0 1 0 0 0 0 0 0
4: 0 0 0 0 1 0 0 0 0
9: 1 0 0 0 0 0 0 0 0
3: 0 0 0 1 0 0 0 0 0
Combining two tables is easy. Add the first table, the second table, and every combination of the two mod 9 (for the first combination, this is equivalent to 2, 4, and 24; for the second, 9, 3, and 93):
0 1 2 3 4 5 6 7 8
24: 0 0 1 0 1 0 1 0 0
93: 1 0 0 2 0 0 0 0 0
Then do it again:
0 1 2 3 4 5 6 7 8
2493: 3 0 2 2 2 2 2 2 0
And there's your answer, sitting there in the 0 column: 3. This corresponds to the substrings 243, 2493, and 9. You don't know that, though, 'cause you only stored counts - and fortunately, you don't care!
Once implemented, this'll give you O(n) performance - you'll just have to figure out exactly how to combine the tables in O(1). But hey - homework, right? Good luck!
If you use int then you shouldnt left shift it too much. If you do, you set the sign bit. Use unsigned int. Or dont left shift too much. You can rightshift once you done if you insist on int.
for the
printf("%ld\n", count);
printf could have problems at displaying long-int types. Did you try cout ?
Here's C++ code according to Akappa's algorithm. However this algorithm fails for numbers that contain one or more 0s i.e. in cases of "10292" and "0189" but gives correct answers for "1292" ans "189". Would appreciate it if anyone could debug this to give answers for all cases.
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<string>
#include<cstring>
#include<vector>
#include<stack>
#include<sstream>
#include<algorithm>
#include<cctype>
#include<list>
#include<set>
#include<set>
#include<map>
using namespace std;
typedef vector<int> table;
table count(string::iterator beg, string::iterator end)
{
table F(9);
std::fill(F.begin(), F.end(), 0);
if (beg == end)
return F;
if (beg + 1 == end) {
F[(*beg - '0') % 9] = 1;
return F;
}
size_t distance = std::distance(beg, end);
string::iterator mid = beg + (distance / 2);
table L = count(beg, mid);
table R = count(mid, end);
for (unsigned int i = 0; i < 9; i++) {
F[i] = L[i] + R[i];
for(unsigned int j = 0; j < 9; j++) {
if (j <= i)
F[i] += L[j] * R[i - j];
else
F[i] += L[j] * R[9 + i - j];
}
}
return F;
}
table count(std::string s)
{
return count(s.begin(), s.end());
}
int main()
{
cout << count("1234")[0] << endl;
cout << count("12349")[0] << endl;
cout << count("9999")[0] << endl;
cout << count("1292")[0] << endl;cout << count("189")[0] << endl;
cout << count("10292")[0] << endl;cout << count("0189")[0] << endl;
system("pause");
}