Combinations based on 2 variables - c

What I'm trying to accomplish is making a function to the following:
Imagine that I have between 1-9 squares. Those squares have a number assigned to them globally, not individually. They are like a set, and that set has this number.
E.g.: | _ | _ | _ | 19
What I'm trying to do is a function that gives me the possible combinations depending on number of squares and the number associated with them. For the example above: 9, 8, 2 is one of the possible combinations. However I just want the numbers that are in those combinations, not the combinations themselves. Plus they have to be unique (shouldn't be 9, 9, 1). Oh and those numbers range from 1-9 only.
How can I achieve this in C? If you are wondering this is for a puzzle game.
Thanks in advance!

Looks like you are trying to find a restricted Partition of the integer on the right. The link should give you a good starting place, and you should be able to find some algorithms that generate partitions of an integer into an arbitrary number of parts.

For future reference, in combinatorics we say "order doesn't matter" to mean "I only want the set of numbers, not a specific ordering"
//Sets the given digit array to contain the "first" set of numbers which sum to sum
void firstCombination(int digits[], int numDigits, int sum) {
reset(digits, 0, 1, numDigits, sum);
}
//Modifies the digit array to contain the "next" set of numbers with the same sum.
//Returns false when no more combinations left
int nextCombination(int digits[], int numDigits) {
int i;
int foundDiffering = 0;
int remaining = 0;
for (i = numDigits - 1; i > 0; i--) {
remaining += digits[i];
if (digits[i] - digits[i - 1] > 1) {
if (foundDiffering || digits[i] - digits[i - 1] > 2) {
digits[i - 1]++;
remaining--;
break;
} else
foundDiffering = 1;
}
}
if (i == 0)
return 0;
else {
reset(digits, i, digits[i - 1] + 1, numDigits - i, remaining);
return 1;
}
}
//Helper method for firstCombination and nextCombination
void reset(int digits[], int off, int lowestValue, int numDigits, int sum) {
int i;
int remaining = sum;
for (i = 0; i < numDigits; i++) {
digits[i + off] = lowestValue;
remaining -= lowestValue;
lowestValue++;
}
int currentDigit = 9;
for (i = numDigits + off - 1; i >= off; i--) {
if (remaining >= currentDigit - digits[i]) {
remaining -= currentDigit - digits[i];
digits[i] = currentDigit;
currentDigit--;
} else {
digits[i] += remaining;
break;
}
}
}

It sounds like what you're working on is very similar to kakuro, also know as Cross Sums: http://en.wikipedia.org/wiki/Cross_Sums
There are generators out there for these kinds of puzzles, for example: http://www.perlmonks.org/?node_id=550884
I suspect that most kakuro generators would have to solve your exact problem, so you might look at some for inspiration.

Related

How to find all the palindromes in a large array?

I need to find all the palindromes of π with 50 million digits 3.141592653589793238462643383279502884197169399375105820974944592307816406286... (goes on and on...)
I've stored all the digits of π in a char array. Now I need to search and count the number of 'palindromes' of length 2 to 15. For example, 535, 979, 33, 88, 14941, etc. are all valid results.
The final output I want is basically like the following.
Palindrome length Number of Palindromes of this length
-----------------------------------------------------------------
2 1234 (just an example)
3 1245
4 689
... ...
... ...
... ...
... ...
15 0
pseudocode of my logic so far - it works but takes forever
//store all digits in a char array
char *piArray = (char *)malloc(NUM_PI_DIGITS * sizeof(char));
int count = 0; //count for the number of palindromes
//because we only need to find palindroms that are 2 - 15 digits long
for(int i = 2; i <= 15; i++){
//loop through the piArray and find all the palindromes with i digits long
for(int j = 0; j < size_of_piArray; j++){
//check if the the sub array piArray[j:j+i] is parlindrom, if so, add a count
bool isPalindrome = true;
for (int k = 0; k < i / 2; k++)
{
if (piArray [j + k] != piArray [j + i - 1 - k])
{
isPalindrom = false;
break;
}
}
if(isPalindrome){
count++;
}
}
}
The problem I am facing now is that it takes too long to loop through the array of this large size (15-2)=13 times. Is there any better way to do this?
Here is a C version adapted from the approach proposed by Caius Jard:
void check_pi_palindromes(int NUM_PI_DIGITS, int max_length, int counts[]) {
// store all digits in a char array
int max_span = max_length / 2;
int start = max_span;
int end = NUM_PI_DIGITS + max_span;
char *pi = (char *)malloc(max_span + NUM_PI_DIGITS + max_span);
// read of generate the digits starting at position `max_span`
[...]
// clear an initial and trailing area to simplify boundary testing
memset(pi, ' ', start);
memset(pi + end, ' ', max_span);
// clear the result array
for (int i = 0; i <= max_length; i++) {
count[i] = 0;
}
// loop through the pi array and find all the palindromes
for (int i = start; i < end; i++) {
if (pi[i + 1] == pi[i - 1]) { //center of an odd length palindrome
count[3]++;
for (n = 2; n <= max_span && pi[i + n] == pi[i - n]; n++) {
count[n * 2 + 1]++;
}
}
if (pi[i] == pi[i - 1]) { //center of an even length palindrome
count[2]++;
for (n = 1; n <= max_span && pi[i + n] == pi[i - n]; n++) {
count[n * 2]++;
}
}
}
}
For each position in the array, it scans in both directions for palindromes of odd and even lengths with these advantages:
single pass through the array
good cache locality because all reads from the array are in a small span from the current position
fewer tests as larger palindromes are only tested as extensions of smaller ones.
A small working prefix and suffix is used to avoid the need to special case the beginning and end of the sequence.
I can't solve it for C, as I'm a C# dev but I expect the conversion will be trivial - I've tried to keep it as basic as possible
char[] pi = "3.141592653589793238462643383279502884197169399375105820974944592307816406286".ToCharArray(); //get a small piece as an array of char
int[] lenCounts = new int[16]; //make a new int array with slots 0-15
for(int i = 1; i < pi.Length-1; i++){
if(pi[i+1] == pi[i-1]){ //center of an odd length pal
int n = 2;
while(pi[i+n] == pi[i-n] && n <= 7) n++;
lenCounts[((n-1)*2+1)]++;
} else if(pi[i] == pi[i-1]){ //center of an even length pal
int n = 1;
while(pi[i+n] == pi[i-1-n] && n <= 7) n++;
lenCounts[n*2]++;
}
}
This demonstrates the "crawl the string looking for a palindrome center then crawl away from it in both directions looking for equal chars" technique..
..the only thing I'm not sure on, and it has occurred in the Pi posted, is what you want to do if palindromes overlap:
3.141592653589793238462643383279502884197169399375105820974944592307816406286
This contains 939 and overlapping with it, 3993. The algo above will find both, so if overlaps are not to be allowed then you might need to extend it to deal with eliminating earlier palindromes if they're overlapped by a longer one found later
You can play with the c# version at https://dotnetfiddle.net/tkQzBq - it has some debug print lines in too. Fiddles are limited to a 10 second execution time so I don't know if you'll be able to time the full 50 megabyte 😀 - you might have to run this algo locally for that one
Edit: fixed a bug in the answer but I haven't fixed it in the fiddle; I did have while(.. n<lenCounts.Length) i.e. allowing n to reach 15, but that would be an issue because it's in both directions.. nshould go to 7 to remain in range of the counts array. I've patched that by hard coding 7 but you might want to make it dependent on array length/2 etc
Well, I think it can't be done less than O(len*n), and that you are doing this O(len^2*n), where 2 <= len <= 15, is almost the same since the K coefficient doesn't change the O notation in this case, but if you want to avoid this extra loop, you can check these links, it shouldn't be hard to add a counter for each length since these codes are counting all of them, with maximum possible length:
source1, source2, source3.
NOTE: Mostly it's better to reach out GeekForGeeks when you are looking for algorithms or optimizations.
EDIT: one of the possible ways with O(n^2) time complexity and O(n)
Auxiliary Space. You can change unordered_map by array if you wish, anyway here the key will be the length and the value will be the count of palindromes with that length.
unordered_map<int, int> countPalindromes(string& s) {
unordered_map<int, int> m;
for (int i = 0; i < s.length(); i++) {
// check for odd length palindromes
for (int j = 0; j <= i; j++) {
if (!s[i + j])
break;
if (s[i - j] == s[i + j]) {
// check for palindromes of length
// greater than 1
if ((i + j + 1) - (i - j) > 1)
m[(i + j + 1) - (i - j)]++;
} else
break;
}
// check for even length palindromes
for (int j = 0; j <= i; j++) {
if (!s[i + j + 1])
break;
if (s[i - j] == s[i + j + 1]) {
// check for palindromes of length
// greater than 1
if ((i + j + 2) - (i - j) > 1)
m[(i + j + 2) - (i - j)]++;
} else
break;
}
}
return m;
}

Luhn Algorithm in C

I'm very new to coding and one of the assignment is to program Luhn's Algorithm. After searching on the internet, everyone's solution looks so different and foreign :( so I don't know where the problem is with my solution. Any help is appreciated!
int main(void)
{
// get card number from user
long number;
do
{
number = get_long("Number: ");
} while (number < 0);
// isolate digits of card number
int digit;
int product;
int sum;
int totalSum;
int counter;
for (counter = 1; number > 9; counter++) {
for (int i = 1; number > 9; i = i * -1) {
digit = number % 10;
// isolate digits that need to be multiplied by 2
if (i == 1) {
product = digit * 2;
// add products' digits
if (product > 9) {
sum = (product % 10) + 1;
}
}
// add sum of digits that weren't multiplied by 2
totalSum = product + sum + digit;
// update "new" number
number = (number - digit) / 10;
}
}
// checksum
int check = totalSum % 10;
if (check != 0) {
printf("INVALID\n");
} else {
printf("VALID\n");
}
}
There are a number of errors in your code, most having to do with how you use variables.
You use totalSum without ever initializing it, which means it can start with any random value!
You add both product and sum to totalSum every time, but you only update their values when some condition applies.
This means at least half the time (maybe more) you add old values you already added previously.
Your loops exit when number is 9 or less, meaning you never check the leftmost (highest) digit of number.
As the comments suggested, you should read the pseudo code in Wikipedia, look carefully what they put in each variable, and what they sum and multiply.

Efficient way to find the sum of digits of an 8 digit number

I have to find the sum of the first 4 digits, the sum of the last 4 digits and compare them (of all the numbers betweem m and n). But when I submit my solution online there's a problem with the time limit.
Here's my code:
#include <stdio.h>
int main()
{
int M, N, res = 0, cnt, first4, second4, sum1, sum2;
scanf("%d", &M);
scanf("%d", &N);
for(cnt = M; cnt <= N; cnt++)
{
first4 = cnt % 10000;
sum1 = first4 % 10 + (first4 / 10) % 10 + (first4 / 100) % 10 + (first4 / 1000) % 10;
second4 = cnt / 10000;
sum2 = second4 % 10 + (second4 / 10) % 10 + (second4 / 100) % 10 + (second4 / 1000) % 10;
if(sum1 == sum2)
res++;
}
printf("%d", res);
return 0;
}
I'm trying to find a more efficient way to do this.
Finally, if you are still interested, there is a much faster way to do this.
Your task doesn't specifically require you to calculate the sums for all the numbers,
it only asks for the number of some special numbers.
In such cases optimization techniques like memoization or dynamic programming come really handy.
In this case, when you have the first four digits of some number (let them be 1234),
you calculate their sum (in this case 10) and you immediately know,
what is the sum of the other four digits supposed to be.
Any 4-digit number, that yields sum 10 can now be the other half to create a valid number.
Therefore total number of valid numbers beginning with 1234 is exactly the number of all four digit numbers that give the sum 10.
Now consider another number, say 3412. This number has also sum equal to 10,
therefore any right-side that completes 1234 also completes 3412.
What this means is that the number of valid numbers beginning with 3412 is the same
as the number of valid numbers beginning with 1234, which is in turn the same as the total number of valid numbers, where the first half yields the sum 10.
Therefore if we precompute for each i the number of four digit numbers
that yield the sum i, we would know for each first four digits the exact number of
combinations of last four digits that complete a valid number,
without having to iterate over all 10000 of them.
The following implementation of this algorithm
Precomputes number of different ending halves for each sum of the beginning half
Splits the [M,N] interval in three subintervals, because in the first and the last beginning not every ending is possible
This algorithm runs quadratically faster than the naive implementation (for sufficiently big N-M).
#include <string.h>
int sum_digits(int number) {
return number%10 + (number/10)%10 + (number/100)%10 + (number/1000)%10;
}
int count(int M, int N) {
if (M > N) return 0;
int ret = 0;
int tmp = 0;
// for each i from 0 to 36 precompute number of ways we can get this sum
// out of a four-digit number
int A[37];
memset(A, 0, 37*4);
for (int i = 0; i <= 9999; ++i) {
++A[sum_digits(i)];
}
// nearest multiple of 10000 greater than M
int near_M = ((M+9999)/10000)*10000;
// nearest multiple of 10000 less than N
int near_N = (N/10000)*10000;
// count all numbers up to first multiple of 10000
tmp = sum_digits(M/10000);
if (near_M <= N) {
for (int i = M; i < near_M; ++i) {
if (tmp == sum_digits(i % 10000)) {
++ret;
}
}
}
// count all numbers between the 10000 multiples, use the precomputed values
for (int i = near_M / 10000; i < near_N / 10000; ++i) {
ret += A[sum_digits(i)];
}
// count all numbers after the last multiple of 10000
tmp = sum_digits(N / 10000);
if (near_N >= M) {
for (int i = near_N; i <= N; ++i) {
if (tmp == sum_digits(i % 10000)) {
++ret;
}
}
}
// special case when there are no multiples of 10000 between M and N
if (near_M > near_N) {
for (int i = M; i <= N; ++i) {
if (sum_digits(i / 10000) == sum_digits(i % 10000)) {
++ret;
}
}
}
return ret;
}
EDIT: I fixed the bugs mentioned in the comments.
I don't know if this would be significantly faster or not, but you might try breaking the number into two 4 digit numbers, then use a table lookup to get the sums. That way there's only one division operation instead of eight.
You can pre-compute the table of 10000 sums so it gets compiled in so there's no runtime cost at all.
Another slightly more complicated, but probably much faster, approach that can be used is have a table or map of 10000 elements that's the reverse of the sum lookup table where you can map the sum to the set of four digit numbers that would produce that sum. That way, when you have to find the result for a particular range 10000 number range, it's a simple lookup on the sum of the most significant four digits. For example, to find the result for the range 12340000 - 12349999, you could use a binary search on the reverse lookup table to quickly find how many numbers in the range 0 - 9999 have the sum 10 (1 + 2 + 3 + 4).
Again - this reverse sum lookup table can be pre-computed and compiled in as a static array.
In this way, the results for complete 10000 number ranges are performed with a couple binary searches. Any partial ranges can also be handled with the reverse lookup table with slightly more complication due to having to ignore matches that are from out of the range of interest. But that complication only has to happen at most twice for your whole set of subranges.
This would reduce the complexity of the algorithm from O(N*N) to O(N log N) (I think).
update:
Here's some timings I got (Win32-x86, using VS 2013 (MSVC 12) with release build default options):
range range
start end count time
================================================
alg1(10000000, 99999999): 4379055, 1.854 seconds
alg2(10000000, 99999999): 4379055, 0.049 seconds
alg3(10000000, 99999999): 4379055, 0.001 seconds
with:
alg1() is the original code from the question
alg2() is my first cut suggestion (lookup precomputed sums)
alg3() is the second suggestion (binary search lookup of sum matches using a table sorted by sums)
I'm actually surprised at the difference between alg1() to alg2()
You are going about this the wrong way. A little bit of cleverness is worth a lot of horsepower. You should not be comparing the first and last four digits of every number.
First - notice that the first four digits will change very slowly - so for sure you can have a loop of 10000 of the last four digits without re-computing the first sum.
Second - the sum of digits repeats itself every 9th number (until you get overflow). This is the basis of the "number is divisible by 9 if sum of digits is divisible by 9". example:
1234 - sum = 10
1234 + 9 = 1243 - sum is still 10
What this means is that the following will work pretty well (pseudo code):
take first 4 digits of M, find sum (call it A)
find sum of last four digits of M (call it B)
subtract: C = (A - B)
If C < 9:
D = C%9
first valid number is [A][B+D]. Then step by 9, until...
You need to think a bit about the "until", and also about what to do when C >= 9. This means you need to find a zero in B and replace it with a 9, then repeat the above.
If you want to do nothing else, then see that you don't need to re-compute the sum of digits that did not change. In general when you add 1 to a number, the sum of digits increases by 1 (unless there is carry - then it decreases by 9; and that happens every 9th, 99th (twice -> sum drops by 18), 999th (drop by 27), etc.
I hope this helps you think about the problem differently.
I am going to try an approach which doesn't make use of the lookup table (even though I know that the second one should be faster) to investigate how much we can speedup just optimizing calculus. This algorithm can be used where stack is an important resource...
Let's work on the idea that divisions and modulus are slow, for example in cortex R4 a 32 bit division requires up to 16 loops while a multiplication can be done in a single loop, with older ARMs things can be even worse.
This basic idea will try to get rid of them using digit arrays instead of integers. To keep it simple let's show an implementation using printf before a pseudo optimized version.
void main() {
int count=0;
int nmax;
char num[9]={0};
int n;
printf( "Insert number1 ");
scanf( "%d", &nm );
printf( "Insert number2 ");
scanf( "%d", &nmax );
while( nm <= nmax ) {
int sumup=0, sumdown=0;
sprintf( num, "%d", nm );
for( n=0; n<4; n++ ) {
sumup += num[n] -'0'; // subtracting '0' is not necessary (see below)
sumdown += num[7-n]-'0'; // subtracting '0' is not necessary (see below)
}
if( sumup == sumdown ) {
/* whatever */
count++;
}
nm++;
}
}
You may want to check that the string is a valid number using strtol before calling the for loop and the length of the string using strlen. I set here fixed values as you required (I assume length always 8).
The downside of the shown algorithm is the sprintf for any loop that may do thing worse... So we apply two major changes
we use [0-9] instead of ['0';'9']
we drop the sprintf for a faster solution which takes in account that we need to format a digit string starting from the previous number (n-1)
Finally the pseudo optimized algorithm should look something like the one shown below in which all divisions and modules are removed (apart from the first number) and bytes are used instead of ASCII.
void pseudo_optimized() {
int count=0;
int nmax,nm;
char num[9]={0};
int sumup=0, sumdown=0;
int n,i;
printf( "Insert number1 ");
scanf( "%d", &nm );
printf( "Insert number2 ");
scanf( "%d", &nmax );
n = nm;
for( i=7; i>=0; i-- ) {
num[i]=n%10;
n/=10;
}
while( nm <= nmax ) {
sumup = num[0] + num[1] + num[2] + num[3];
sumdown = num[7] + num[6] + num[5] + num[4];
if( sumup == sumdown ) {
/* whatever */
count++;
}
nm++;
/* Following loop is a faster sprintf replacement and
* it will exit at the first value 9 times on 10
*/
for( i=7; i>=0; i-- ) {
if( num[i] == 9 ) {
num[i]=0;
} else {
num[i] += 1;
break;
}
}
}
}
Original algo on my vm 5.500000 s, this algo 0.950000 s tested for [00000000=>99999999]
The weak point of this algorithm is that it uses sum of digits (which are not necessary and a for...loop that can be unrolled.
* update *
further optimization. The sums of digits are not necessary.... thinking about it I could improve the algorithm in the following way:
int optimized() {
int nmax=99999999,
int nm=0;
clock_t time1, time2;
char num[9]={0};
int sumup=0, sumdown=0;
int n,i;
int count=0;
n = nm;
time1 = clock();
for( i=7; i>=0; i-- ) {
num[i]=n%10;
n/=10;
}
sumup = num[0] + num[1] + num[2] + num[3];
sumdown = num[7] + num[6] + num[5] + num[4];
while( nm <= nmax ) {
if( sumup == sumdown ) {
count++;
}
nm++;
for( i=7; i>=0; i-- ) {
if( num[i] == 9 ) {
num[i]=0;
if( i>3 )
sumdown-=9;
else
sumup-=9;
} else {
num[i] += 1;
if( i>3 )
sumdown++;
else
sumup++;
break;
}
}
}
time2 = clock();
printf( "Final-now %d %f\n", count, ((float)time2 - (float)time1) / 1000000);
return 0;
}
with this we arrive to 0.760000 s which is 3 times slower than the result achieved on the same machine using lookup tables.
* update* Optimized and unrolled:
int optimized_unrolled(int nm, int nmax) {
char num[9]={0};
int sumup=0, sumdown=0;
int n,i;
int count=0;
n = nm;
for( i=7; i>=0; i-- ) {
num[i]=n%10;
n/=10;
}
sumup = num[0] + num[1] + num[2] + num[3];
sumdown = num[7] + num[6] + num[5] + num[4];
while( nm <= nmax ) {
if( sumup == sumdown ) {
count++;
}
nm++;
if( num[7] == 9 ) {
num[7]=0;
if( num[6] == 9 ) {
num[6]=0;
if( num[5] == 9 ) {
num[5]=0;
if( num[4] == 9 ) {
num[4]=0;
sumdown=0;
if( num[3] == 9 ) {
num[3]=0;
if( num[2] == 9 ) {
num[2]=0;
if( num[1] == 9 ) {
num[1]=0;
num[0]++;
sumup-=26;
} else {
num[1]++;
sumup-=17;
}
} else {
num[2]++;
sumup-=8;
}
} else {
num[3]++;
sumup++;
}
} else {
num[4]++;
sumdown-=26;
}
} else {
num[5]++;
sumdown-=17;
}
} else {
num[6]++;
sumdown-=8;
}
} else {
num[7]++;
sumdown++;
}
}
return count;
}
Unrolling vectors improves the speed of about 50%. The algorithm costs now 0.36000 s, by the way it makes use of the stack a bit more than the previous solution (as some 'if' statements may result in a push, so it cannot be always used). The result is comparable with Alg2#Michael Burr on the same machine, [Alg3-Alg5]#Michael Burr are a lot faster where stack isn't a concern.
Note all test where performed on a intel VMS. I will try to run all those algos on a ARM device if I will have time.
#include <stdio.h>
int main(){
int M, N;
scanf("%d", &M);
scanf("%d", &N);
static int table[10000] = {0,1,2,3,4,5,6,7,8,9};
{
register int i=0,i1,i2,i3,i4;
for(i1=0;i1<10;++i1)
for(i2=0;i2<10;++i2)
for(i3=0;i3<10;++i3)
for(i4=0;i4<10;++i4)
table[i++]=table[i1]+table[i2]+table[i3]+table[i4];
}
register int cnt = M, second4 = M % 10000;
int res = 0, first4 = M / 10000, sum1=table[first4];
for(; cnt <= N; ++cnt){
if(sum1 == table[second4])
++res;
if(++second4>9999){
second4 -=10000;
if(++first4>9999)break;
sum1 = table[first4];
}
}
printf("%d", res);
return 0;
}
If you know that the numbers are fixed like that, then you can you substring functions to get the components and compare them. Otherwise, your modulator operations are contributing unnecessary time.
i found faster algorithm:
#include <stdio.h>
#include <ctime>
int main()
{
clock_t time1, time2;
int M, N, res = 0, cnt, first4, second4, sum1, sum2,last4_ofM,first4_ofM,last4_ofN,first4_ofN,j;
scanf("%d", &M);
scanf("%d", &N);
time1 = clock();
for(cnt = M; cnt <= N; cnt++)
{
first4 = cnt % 10000;
sum1 = first4 % 10 + (first4 / 10) % 10 + (first4 / 100) % 10 + (first4 / 1000) % 10;
second4 = cnt / 10000;
sum2 = second4 % 10 + (second4 / 10) % 10 + (second4 / 100) % 10 + (second4 / 1000) % 10;
if(sum1 == sum2)
res++;
}
time2 = clock();
printf("%d\n", res);
printf("first algorithm time: %f\n",((float)time2 - (float)time1) / 1000000.0F );
res=0;
time1 = clock();
first4_ofM = M / 10000;
last4_ofM = M % 10000;
first4_ofN = N / 10000;
last4_ofN = N % 10000;
for(int i = first4_ofM; i <= first4_ofN; i++)
{
sum1 = i % 10 + (i / 10) % 10 + (i / 100) % 10 + (i / 1000) % 10;
if ( i == first4_ofM )
j = last4_ofM;
else
j = 0;
while ( j <= 9999)
{
sum2 = j % 10 + (j / 10) % 10 + (j / 100) % 10 + (j / 1000) % 10;
if(sum1 == sum2)
res++;
if ( i == first4_ofN && j == last4_ofN ) break;
j++;
}
}
time2 = clock();
printf("%d\n", res);
printf("second algorithm time: %f\n",((float)time2 - (float)time1) / 1000000.0F );
return 0;
}
i just dont need to count sum of the first four digits all the time the number in changed. I need to count it one time per 10000 iterations. In worst case output is:
10000000
99999999
4379055
first algorithm time: 5.160000
4379055
second algorithm time: 2.240000
about half the better result.

Printing to output: integer as sum of powers of 2

I had an exam, and I've been struggling ever since.
You have an array of integers(ex. 13, 6, 21, 4), and I need to make an output that looks like:
13 = 2^3 + 2^2 + 2^0
6 = 2^2 + 2^1
21 = 2^4 + 2^2 + 2^0
4 = 2^2
here's what i've got so far.
#include <stdio.h>
#define MAX 100
int main() {
int niz[MAX], nizb, n, i, ones, k;
while(1) {
printf("Array length: ");
scanf("%d", &n);
if (n<=0 || n>MAX) break;
printf("Array elements: ");
for(i=0;i<n;i++){
scanf("%d", &niz[i]);
if (niz[i] <=0) {
printf("Error! Wrong value. Enter new one: ");
scanf("%d", &niz[i]);
}
}
for(i=0;i<n;i++) {
nizb = niz[i];
ones = 0;
for(k=0; k < 16; k++) {
//What should i do here?
}
}
}
}
I'm stuck here. I dont know how many bits should i use, and how does C sees those bits of integer. I'm using var 'k' to add to a string that is in format '2^3 + 2^2 ...', where k is the value of 'for' iteration. I have made an assumption that length of the integer is 16, but im really not sure since we do this on a sheet of paper.
I want to say BIG THANKS TO EVERYONE!!!
You can calculate how many bits to use by using the sizeof operator and CHAR_BIT:
int bitsPerInt = sizeof(int) * CHAR_BIT;
CHAR_BIT is definied in limits.h.
After you have that limit, you can use the bitwise & operator to extract each bit:
for (k = bitsPerInt - 1; k >= 0; k--)
{
if (nizb & (1U << k))
// output
else
// don't
}
I'll leave the details up to you.
Aside: It looks like you're trying to use niz as an array, but you haven't declared it as one. Does this code even compile? Also, the return value of main should be int.
Not sure what this has to do with twos-complement (which is a particular way of representing negative numbers). What you are trying to do is express an integer as a sum of powers of 2, apparently. Here's the way I'd do it, which isn't necessarily better or worse than the other answers...
void powersum(int n)
{ int powers[sizeof(int) << 3];
int i;
char *sep = "";
printf("%d = ", n);
powers[0] = 0;
for (i = 0; n; n >>= 1, ++i)
powers[i] = n & 1;
while (--i >= 0)
{ if (powers[i])
{ printf("%s2^%d", sep, i);
sep = " + ";
}
}
printf("\n");
}
EDIT: Here's another version that doesn't use the stack-allocated array, but as a tradeoff has to go around the loop more (once for each bit, as opposed to only looping until the highest 1-bit is found):
void powersum2(int n)
{ int i = (sizeof(int) << 3) - 2;
int m = 1 << i;
char *sep = "";
printf("%d = ", n);
while (m)
{ if (n & m)
{ printf("%s2^%d", sep, i);
sep = " + ";
}
m >>= 1;
--i;
}
printf("\n");
}
This is complete conjecture, since I'm not really good with math, but I think I'd go about it like this:
int potency = 0, base = 1;
while(base < NumberInQuestion) {
base *= 2;
++potency;
}
After the loop finishes, you'll know the highest potency which still fits into 'Number'.
Number -= base/2; //Removes the base you just calculated from the number.
printf("2^%d", potency);
Rinse and repeat, until Number falls to 0, which should be at 2^0 at latest.
For your use-case, the code may look somewhat like this:
for(i=0; i < n; ++i) {
int Number = niz[i];
while(Number > 0) {
int potency = 0, base = 1;
do { //Executes at least once, making a number of '1' possible.
base *= 2;
++potency;
} while(base < Number);
Number -= base/2; //Reverts the last step you made, making the 'base' smaller than 'Number'.
printf("2^%d", potency);
}
}
There's a possible alternative, which can give you a more complete picture of things and will save you iterations. For this we use a two-step process.
for(i=0; i < n; ++i) {
int Number = niz[i];
int potency = 0, base = 1;
do { //Executes at least once, making a number of '1' possible.
base *= 2;
++potency;
} while(base < Number);
base /= 2; //Reverses the last iteration.
//At this point, we know the maximum potency, which still fits into the number.
//In regards of base 2, we know the Most Significant Bit.
while(base > 0) {
Number -= base; //Removes the MSD (Most significant digit)
printf("2^%d", potency); //Prints your '1'.
while(base > Number) { //Executes at least once.
base /= 2; //Goes back one potency. (Ends at '0' latest.)
--potency; //For each potency (except for first), it's a '0'.
}
}
}
quotient = niz[i];
int k=0,c[MAX];
while(quotient!=0){
binaryNumber[i++]= quotient % 2; //this will convert your numbers to binary form
quotient = quotient / 2; //and store in reverse in array
}
for(j = 0 ;j<i;j++)
{
if(binaryNumber[j]==1) */e.g binary of 4 is stored in array as 001 ie 1 atpos2*/
{ c[k]=j;
k++;}
}
while(k--)
printf("2^%d +",c[k]);
If you can tolerate a GCC-dependency, a hack on #twalberg's solution get's really nice and small ;)
void powersum(int n)
{
char *sep = "";
printf("%d = ", n);
while (n) {
int pos = 31 - __builtin_clz(n);
printf("%s2^%d", sep, pos);
sep = " + ";
n ^= 1 << pos;
}
printf("\n");
}

Faster algorithm to find how many numbers are not divisible by a given set of numbers

I am trying to solve an online judge problem: http://opc.iarcs.org.in/index.php/problems/LEAFEAT
The problem in short:
If we are given an integer L and a set of N integers s1,s2,s3..sN, we have to find how many numbers there are from 0 to L-1 which are not divisible by any of the 'si's.
For example, if we are given, L = 20 and S = {3,2,5} then there are 6 numbers from 0 to 19 which are not divisible by 3,2 or 5.
L <= 1000000000 and N <= 20.
I used the Inclusion-Exclusion principle to solve this problem:
/*Let 'T' be the number of integers that are divisible by any of the 'si's in the
given range*/
for i in range 1 to N
for all subsets A of length i
if i is odd then:
T += 1 + (L-1)/lcm(all the elements of A)
else
T -= 1 + (L-1)/lcm(all the elements of A)
return T
Here is my code to solve this problem
#include <stdio.h>
int N;
long long int L;
int C[30];
typedef struct{int i, key;}subset_e;
subset_e A[30];
int k;
int gcd(a,b){
int t;
while(b != 0){
t = a%b;
a = b;
b = t;
}
return a;
}
long long int lcm(int a, int b){
return (a*b)/gcd(a,b);
}
long long int getlcm(int n){
if(n == 1){
return A[0].key;
}
int i;
long long int rlcm = lcm(A[0].key,A[1].key);
for(i = 2;i < n; i++){
rlcm = lcm(rlcm,A[i].key);
}
return rlcm;
}
int next_subset(int n){
if(k == n-1 && A[k].i == N-1){
if(k == 0){
return 0;
}
k--;
}
while(k < n-1 && A[k].i == A[k+1].i-1){
if(k <= 0){
return 0;
}
k--;
}
A[k].key = C[A[k].i+1];
A[k].i++;
return 1;
}
int main(){
int i,j,add;
long long int sum = 0,g,temp;
scanf("%lld%d",&L,&N);
for(i = 0;i < N; i++){
scanf("%d",&C[i]);
}
for(i = 1; i <= N; i++){
add = i%2;
for(j = 0;j < i; j++){
A[j].key = C[j];
A[j].i = j;
}
temp = getlcm(i);
g = 1 + (L-1)/temp;
if(add){
sum += g;
} else {
sum -= g;
}
k = i-1;
while(next_subset(i)){
temp = getlcm(i);
g = 1 + (L-1)/temp;
if(add){
sum += g;
} else {
sum -= g;
}
}
}
printf("%lld",L-sum);
return 0;
}
The next_subset(n) generates the next subset of size n in the array A, if there is no subset it returns 0 otherwise it returns 1. It is based on the algorithm described by the accepted answer in this stackoverflow question.
The lcm(a,b) function returns the lcm of a and b.
The get_lcm(n) function returns the lcm of all the elements in A.
It uses the property : LCM(a,b,c) = LCM(LCM(a,b),c)
When I submit the problem on the judge it gives my a 'Time Limit Exceeded'. If we solve this using brute force we get only 50% of the marks.
As there can be upto 2^20 subsets my algorithm might be slow, hence I need a better algorithm to solve this problem.
EDIT:
After editing my code and changing the function to the Euclidean algorithm, I am getting a wrong answer, but my code runs within the time limit. It gives me a correct answer to the example test but not to any other test cases; here is a link to ideone where I ran my code, the first output is correct but the second is not.
Is my approach to this problem correct? If it is then I have made a mistake in my code, and I'll find it; otherwise can anyone please explain what is wrong?
You could also try changing your lcm function to use the Euclidean algorithm.
int gcd(int a, int b) {
int t;
while (b != 0) {
t = b;
b = a % t;
a = t;
}
return a;
}
int lcm(int a, int b) {
return (a * b) / gcd(a, b);
}
At least with Python, the speed differences between the two are pretty large:
>>> %timeit lcm1(103, 2013)
100000 loops, best of 3: 9.21 us per loop
>>> %timeit lcm2(103, 2013)
1000000 loops, best of 3: 1.02 us per loop
Typically, the lowest common multiple of a subset of k of the s_i will exceed L for k much smaller than 20. So you need to stop early.
Probably, just inserting
if (temp >= L) {
break;
}
after
while(next_subset(i)){
temp = getlcm(i);
will be sufficient.
Also, shortcut if there are any 1s among the s_i, all numbers are divisible by 1.
I think the following will be faster:
unsigned gcd(unsigned a, unsigned b) {
unsigned r;
while(b) {
r = a%b;
a = b;
b = r;
}
return a;
}
unsigned recur(unsigned *arr, unsigned len, unsigned idx, unsigned cumul, unsigned bound) {
if (idx >= len || bound == 0) {
return bound;
}
unsigned i, g, s = arr[idx], result;
g = s/gcd(cumul,s);
result = bound/g;
for(i = idx+1; i < len; ++i) {
result -= recur(arr, len, i, cumul*g, bound/g);
}
return result;
}
unsigned inex(unsigned *arr, unsigned len, unsigned bound) {
unsigned i, result = bound, t;
for(i = 0; i < len; ++i) {
result -= recur(arr, len, i, 1, bound);
}
return result;
}
call it with
unsigned S[N] = {...};
inex(S, N, L-1);
You need not add the 1 for the 0 anywhere, since 0 is divisible by all numbers, compute the count of numbers 1 <= k < L which are not divisible by any s_i.
Create an array of flags with L entries. Then mark each touched leaf:
for(each size in list of sizes) {
length = 0;
while(length < L) {
array[length] = TOUCHED;
length += size;
}
}
Then find the untouched leaves:
for(length = 0; length < L; length++) {
if(array[length] != TOUCHED) { /* Untouched leaf! */ }
}
Note that there is no multiplication and no division involved; but you will need up to about 1 GiB of RAM. If RAM is a problem the you can use an array of bits (max. 120 MiB).
This is only a beginning though, as there are repeating patterns that can be copied instead of generated. The first pattern is from 0 to S1*S2, the next is from 0 to S1*S2*S3, the next is from 0 to S1*S2*S3*S4, etc.
Basically, you can set all values touched by S1 and then S2 from 0 to S1*S2; then copy the pattern from 0 to S1*S2 until you get to S1*S2*S3 and set all the S3's between S3 and S1*S2*S3; then copy that pattern until you get to S1*S2*S3*S4 and set all the S4's between S4 and S1*S2*S3*S4 and so on.
Next; if S1*S2*...Sn is smaller than L, you know the pattern will repeat and can generate the results for lengths from S1*S2*...Sn to L from the pattern. In this case the size of the array only needs to be S1*S2*...Sn and doesn't need to be L.
Finally, if S1*S2*...Sn is larger than L; then you could generate the pattern for S1*S2*...(Sn-1) and use that pattern to create the results from S1*S2*...(Sn-1) to S1*S2*...Sn. In this case if S1*S2*...(Sn-1) is smaller than L then the array doesn't need to be as large as L.
I'm afraid your problem understanding is maybe not correct.
You have L. You have a set S of K elements. You must count the sum of quotient of L / Si. For L = 20, K = 1, S = { 5 }, the answer is simply 16 (20 - 20 / 5). But K > 1, so you must consider the common multiples also.
Why loop through a list of subsets? It doesn't involve subset calculation, only division and multiple.
You have K distinct integers. Each number could be a prime number. You must consider common multiples. That's all.
EDIT
L = 20 and S = {3,2,5}
Leaves could be eaten by 3 = 6
Leaves could be eaten by 2 = 10
Leaves could be eaten by 5 = 4
Common multiples of S, less than L, not in S = 6, 10, 15
Actually eaten leaves = 20/3 + 20/2 + 20/5 - 20/6 - 20/10 - 20/15 = 6
You can keep track of the distance until then next touched leaf for each size. The distance to the next touched leaf will be whichever distance happens to be smallest, and you'd subtract this distance from all the others (and wrap whenever the distance is zero).
For example:
int sizes[4] = {2, 5, 7, 9};
int distances[4];
int currentLength = 0;
for(size = 0 to 3) {
distances[size] = sizes[size];
}
while(currentLength < L) {
smallest = INT_MAX;
for(size = 0 to 3) {
if(distances[size] < smallest) smallest = distances[size];
}
for(size = 0 to 3) {
distances[size] -= smallest;
if(distances[size] == 0) distances[size] = sizes[size];
}
while( (smallest > 1) && (currentLength < L) ) {
currentLength++;
printf("%d\n", currentLength;
smallest--;
}
}
#A.06: u r the one with username linkinmew on opc, rite?
Anyways, the answer just requires u to make all possible subsets, and then apply inclusion exclusion principle. This will fall well within the time bounds for the data given. For making all possible subsets, u can easily define a recursive function.
i don't know about programming but in math there is a single theorem which works on a set that has GCD 1
L=20, S=(3,2,5)
(1-1/p)(1-1/q)(1-1/r).....and so on
(1-1/3)(1-1/2)(1-1/5)=(2/3)(1/2)(4/5)=4/15
4/15 means there are 4 numbers in each set of 15 number which are not divisible by any number rest of it can be count manually eg.
16, 17, 18, 19, 20 (only 17 and 19 means there are only 2 numbers thatr can't be divided by any S)
4+2=6
6/20 means there are only 6 numbers in first 20 numbers that can't be divided by any s

Resources