project-euler-solutions/C/projecteuler.c
Daniele Fucini f017e59241
Add more solutions in C
Added solutions for problem 51, 52, 53, 54 and 55 in C.
2019-09-25 17:43:40 +02:00

427 lines
9.4 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <gmp.h>
#include "projecteuler.h"
int partition(void **array, int l, int r, int (*cmp)(void *lv, void *rv));
int is_prime(long int num)
{
long int i, limit;
if(num <= 3)
{
/* If num is 2 or 3 then it's prime.*/
return num == 2 || num == 3;
}
/* If num is divisible by 2 or 3 then it's not prime.*/
if(num % 2 == 0 || num % 3 == 0)
{
return 0;
}
/* Any number can have only one prime factor greater than its
* square root. If we reach the square root and we haven't found
* any smaller prime factors, then the number is prime.*/
limit = floor(sqrt(num));
/* Every prime other than 2 and 3 is in the form 6k+1 or 6k-1.
* If I check all those value no prime factors of the number
* will be missed. If a factor is found, the number is not prime
* and the function returns 0.*/
for(i = 5; i <= limit; i += 6)
{
if(num % i == 0 || num % (i + 2) == 0)
{
return 0;
}
}
/* If no factor is found up to the square root of num, num is prime.*/
return 1;
}
int is_palindrome(int num, int base)
{
int reverse = 0, tmp;
tmp = num;
/* Start with reverse=0, get the rightmost digit of the number using
* modulo operation (num modulo base), add it to reverse. Remove the
* rightmost digit from num dividing num by the base, shift the reverse left
* multiplying by the base, repeat until all digits have been inserted
* in reverse order.*/
while(tmp > 0)
{
reverse *= base;
reverse += tmp % base;
tmp /= base;
}
/* If the reversed number is equal to the original one, then it's palindrome.*/
if(num == reverse)
{
return 1;
}
return 0;
}
/* Same function, using GMP Library for long numbers.*/
int is_palindrome_mpz(mpz_t num, int base)
{
mpz_t tmp, reverse, rem;
mpz_inits(tmp, reverse, rem, NULL);
mpz_set(tmp, num);
mpz_set_ui(reverse, 0);
while(mpz_cmp_ui(tmp, 0) > 0)
{
mpz_mul_ui(reverse, reverse, base);
mpz_tdiv_qr_ui(tmp, rem, tmp, base);
mpz_add(reverse, reverse, rem);
}
if(!mpz_cmp(num, reverse))
{
mpz_clears(reverse, rem, NULL);
return 1;
}
mpz_clears(reverse, rem, NULL);
return 0;
}
long int gcd(long int a, long int b)
{
/* Euclid's algorithm for the greatest common divisor:
* gcd(a, 0) = a
* gcd(a, b) = gcd(b, a modulo b)*/
if(b == 0)
{
return a;
}
return gcd(b, a%b);
}
/* Least common multiple algorithm using the greatest common divisor.*/
long int lcm(long int a, long int b)
{
return a * b / gcd(a, b);
}
/* Recursive function to calculate the least common multiple of more than 2 numbers.*/
long int lcmm(long int *values, int n)
{
int i;
long int value;
/* If there are only two numbers, use the lcm function to calculate the lcm.*/
if(n == 2)
{
return lcm(values[0], values[1]);
}
else
{
value = values[0];
for(i = 0; i < n - 1; i++)
{
values[i] = values[i+1];
}
/* Recursively calculate lcm(a, b, c, ..., n) = lcm(a, lcm(b, c, ..., n)).*/
return lcm(value, lcmm(values, n-1));
}
}
/* Function implementing the Sieve or Eratosthenes to generate
* primes up to a certain number.*/
int *sieve(int n)
{
int i, j, limit;
int *primes;
if((primes = (int *)malloc(n*sizeof(int))) == NULL)
{
return NULL;
}
/* 0 and 1 are not prime, 2 and 3 are prime.*/
primes[0] = 0;
primes[1] = 0;
primes[2] = 1;
primes[3] = 1;
/* Cross out (set to 0) all even numbers and set the odd numbers to 1 (possible prime).*/
for(i = 4; i < n - 1; i += 2)
{
primes[i] = 0;
primes[i+1] = 1;
}
/* If i is prime, all multiples of i smaller than i*i have already been crossed out.
* if i=sqrt(n), all multiples of i up to n (the target) have been crossed out. So
* there is no need check i>sqrt(n).*/
limit = floor(sqrt(n));
for(i = 3; i <= limit; i += 2)
{
/* Find the next number not crossed out, which is prime.*/
if(primes[i])
{
/* Cross out all multiples of i, starting with i*i because any smaller multiple
* of i has a smaller prime factor and has already been crossed out. Also, since
* i is odd, i*i+i is even and has already been crossed out, so multiples are
* crossed out with steps of 2*i.*/
for(j = i * i; j < n; j += 2 * i)
{
primes[j] = 0;
}
}
}
return primes;
}
int count_divisors(int n)
{
int i, limit, count = 0;
/* For every divisor below the square root of n, there is a corresponding one
* above the square root, so it's sufficient to check up to the square root of n
* and count every divisor twice. If n is a perfect square, the last divisor is
* wrongly counted twice and must be corrected.*/
limit = floor(sqrt(n));
for(i = 1; i <= limit; i++)
{
if(n % i == 0)
{
count += 2;
}
}
if(n == limit * limit)
{
count--;
}
return count;
}
int find_max_path(int **triang, int n)
{
int i, j;
/* Start from the second to last row and go up.*/
for(i = n - 2; i >= 0; i--)
{
/* For each element in the row, check the two adjacent elements
* in the row below and sum the larger one to it. At the end,
* the element at the top will contain the value of the maximum path.*/
for(j = 0; j <= i; j++)
{
if(triang[i+1][j] > triang[i+1][j+1])
triang[i][j] += triang[i+1][j];
else
triang[i][j] += triang[i+1][j+1];
}
}
return triang[0][0];
}
int sum_of_divisors(int n)
{
int i, sum = 1, limit;
/* For each divisor of n smaller than the square root of n,
* there is another one larger than the square root. If i is
* a divisor of n, so is n/i. Checking divisors i up to square
* root of n and adding both i and n/i is sufficient to sum
* all divisors.*/
limit = floor(sqrt(n));
for(i = 2; i <= limit; i++)
{
if(n % i == 0)
{
sum += i;
/* If n is a perfect square, i=limit is a divisor and
* has to be counted only once.*/
if(n != i * i)
{
sum += (n / i);
}
}
}
return sum;
}
void insertion_sort(void **array, int l, int r, int (*cmp)(void *lv, void *rv))
{
int i, j;
void *tmp;
/* After this cycle the smallest element will be in the first position of the array.*/
for(i = r; i > l; i--)
{
if(cmp(array[i], array[i-1]) < 0)
{
tmp = array[i];
array[i] = array[i-1];
array[i-1] = tmp;
}
}
/* For each element in the array (starting from i=2), move it to the left until a
* smaller element on its left is found.*/
for(i = l + 2; i <= r; i++)
{
tmp = array[i];
j = i;
while(cmp(tmp, array[j-1]) < 0)
{
array[j] = array[j-1];
j--;
}
array[j] = tmp;
}
}
int partition(void **array, int l, int r, int (*cmp)(void *lv, void *rv))
{
int i = l -1, j = r;
void *pivot, *tmp;
/* Arbitrarily selecting the rightmost element as pivot.*/
pivot = array[r];
while(1)
{
/* From the left, loop until an element greater than the pivot is found.*/
while(cmp(array[++i], pivot) < 0);
/* From the right, loop until an element smaller than the pivot is found
* or the beginning of the array is reached.*/
while(cmp(array[--j], pivot) > 0)
{
if(j == l)
{
break;
}
}
/* If j<=i, array[j], which is smaller than pivot, is already on the left
* of array[i], which is larger than pivot, so they don't need to be swapped.*/
if(j <= i)
{
break;
}
/* If j>i, swap array[i] and array[j].*/
tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
/* Swap array[i] with pivot. All elements on the left of pivot are smaller, all
* the elements on the right are bigger, so pivot is in the correct position
* in the sorted array.*/
tmp = array[i];
array[i] = array[r];
array[r] = tmp;
return i;
}
void quick_sort(void **array, int l, int r, int (*cmp)(void *lv, void *rv))
{
int i;
/* If the array is small, it's better to just use a simple insertion_sort algorithm.*/
if(r - l <= 20)
{
insertion_sort(array, l, r, cmp);
return;
}
/* Partition the array and recursively run quick_sort on the two partitions.*/
i = partition(array, l, r, cmp);
quick_sort(array, l, i-1, cmp);
quick_sort(array, i+1, r, cmp);
}
int is_pandigital(int value, int n)
{
int *digits;
int i, digit;
if((digits = (int *)calloc(n+1, sizeof(int))) == NULL)
{
fprintf(stderr, "Error while allocating memory\n");
exit(1);
}
for(i = 0; i < n && value > 0; i++)
{
digit = value % 10;
if(digit > n)
{
return 0;
}
digits[digit]++;
value /= 10;
}
if(i < n || value > 0)
{
free(digits);
return 0;
}
if(digits[0] != 0)
{
free(digits);
return 0;
}
for(i = 1; i <= n; i++)
{
if(digits[i] != 1)
{
free(digits);
return 0;
}
}
free(digits);
return 1;
}
int is_pentagonal(long int n)
{
double i;
i = (sqrt(24*n+1) + 1) / 6;
if(i == (int)i)
{
return 1;
}
else
{
return 0;
}
}