Improve solutions for problems 18, 24 and 25

This commit is contained in:
daniele 2019-09-23 20:13:32 +02:00
parent 593d52144d
commit b4c85f8f4a
Signed by: fuxino
GPG Key ID: 6FE25B4A3EE16FDA
7 changed files with 187 additions and 99 deletions

View File

@ -74,6 +74,7 @@ int main(int argc, char **argv)
fclose(fp); fclose(fp);
/* Use function implemented in projecteuler.c to find the maximum path.*/
max = find_max_path(triang, 15); max = find_max_path(triang, 15);
clock_gettime(CLOCK_MONOTONIC, &end); clock_gettime(CLOCK_MONOTONIC, &end);

136
C/p024.c
View File

@ -1,24 +1,59 @@
/* A permutation is an ordered arrangement of objects. For example, 3124 is one possible permutation of the digits 1, 2, 3 and 4.
* If all of the permutations are listed numerically or alphabetically, we call it lexicographic order. The lexicographic permutations of 0, 1 and 2 are:
*
* 012 021 102 120 201 210
*
* What is the millionth lexicographic permutation of the digits 0, 1, 2, 3, 4, 5, 6, 7, 8 and 9?*/
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <time.h> #include <time.h>
#include "projecteuler.h"
void next_perm(int *perm, int n); void next_perm(int **perm, int n);
void swap(int *vet, int i, int j); void swap(int **vet, int i, int j);
void sort(int *vet, int i, int n); int compare(void *a, void *b);
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int i, perm[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; int i, res[10];
int **perm;
double elapsed; double elapsed;
struct timespec start, end; struct timespec start, end;
clock_gettime(CLOCK_MONOTONIC, &start); clock_gettime(CLOCK_MONOTONIC, &start);
if((perm = (int **)malloc(10*sizeof(int *))) == NULL)
{
fprintf(stderr, "Error while allocating memory\n");
return 1;
}
for(i = 0; i < 10; i++)
{
if((perm[i] = (int *)malloc(sizeof(int))) == NULL)
{
fprintf(stderr, "Error while allocating memory\n");
return 1;
}
*perm[i] = i;
}
for(i = 0; i < 999999; i++) for(i = 0; i < 999999; i++)
{ {
/* Function that generates permutations in lexicographic order.
* Finish when the 1000000th is found.*/
next_perm(perm, 10); next_perm(perm, 10);
} }
for(i = 0; i < 10; i++)
{
res[i] = *perm[i];
free(perm[i]);
}
free(perm);
clock_gettime(CLOCK_MONOTONIC, &end); clock_gettime(CLOCK_MONOTONIC, &end);
printf("Project Euler, Problem 24\n"); printf("Project Euler, Problem 24\n");
@ -26,7 +61,7 @@ int main(int argc, char **argv)
for(i = 0; i < 10; i++) for(i = 0; i < 10; i++)
{ {
printf("%d", perm[i]); printf("%d", res[i]);
} }
printf("\n"); printf("\n");
@ -38,61 +73,56 @@ int main(int argc, char **argv)
return 0; return 0;
} }
void next_perm(int *perm, int n) void swap(int **vet, int i, int j)
{ {
int i, j, min = n, min_idx, flag = 0; int *tmp;
for(i = 0; i < n - 1; i++)
{
if(perm[i] < perm[i+1])
{
flag=1;
break;
}
}
if(!flag)
{
return;
}
for(i = n - 2; perm[i] > perm[i+1]; i--);
for(j = i + 1; j < n; j++)
{
if(perm[j] > perm[i] && perm[j] < min)
{
min = perm[j];
min_idx = j;
}
}
swap(perm, i, min_idx);
sort(perm, i+1, n);
}
void swap(int *vet, int i, int j)
{
int tmp;
tmp = vet[i]; tmp = vet[i];
vet[i] = vet[j]; vet[i] = vet[j];
vet[j] = tmp; vet[j] = tmp;
} }
void sort(int *vet, int i, int j) int compare(void *a, void *b)
{ {
int a, b, tmp; int *n1, *n2;
for(a=i+1; a<j; a++) n1 = (int *)a;
{ n2 = (int *)b;
tmp=vet[a];
b=a-1; return *n1 - *n2;
while(b>=i && vet[b]>tmp) }
{
vet[b+1]=vet[b]; /* Implements SEPA (Simple, Efficient Permutation Algorithm)
b--; * to find the next permutation.*/
} void next_perm(int **perm, int n)
vet[b+1]=tmp; {
} int i, key;
/* Starting from the right of the array, for each pair of values
* if the left one is smaller than the right, that value is the key.*/
for(i = n - 2; i >= 0; i--)
{
if(compare((void *)perm[i], (void *)perm[i+1]) < 0)
{
key = i;
break;
}
}
/* If no left value is smaller than its right value, the
* array is in reverse order, i.e. it's the last permutation.*/
if(i == -1)
{
return;
}
/* Find the smallest value on the right of the key which is bigger than the key itself,
* considering that the values at the right of the key are in reverse order.*/
for(i = key + 1; i < n && compare((void *)perm[i], (void *)perm[key]) > 0; i++);
/* Swap the value found and the key.*/
swap(perm, key, i-1);
/* Sort the values at the right of the key. This is
* the next permutation.*/
insertion_sort((void **)perm, key+1, n-1, compare);
} }

View File

@ -1,3 +1,24 @@
/* The Fibonacci sequence is defined by the recurrence relation:
*
* Fn = Fn1 + Fn2, where F1 = 1 and F2 = 1.
* Hence the first 12 terms will be:
* F1 = 1
* F2 = 1
* F3 = 2
* F4 = 3
* F5 = 5
* F6 = 8
* F7 = 13
* F8 = 21
* F9 = 34
* F10 = 55
* F11 = 89
* F12 = 144
*
* The 12th term, F12, is the first term to contain three digits.
*
* What is the index of the first term in the Fibonacci sequence to contain 1000 digits?*/
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -9,30 +30,36 @@ int main(int argc, char **argv)
int i; int i;
double elapsed; double elapsed;
struct timespec start, end; struct timespec start, end;
mpz_t a, b; mpz_t f1, f2, fn;
char *num; char *num;
size_t size; size_t size;
clock_gettime(CLOCK_MONOTONIC, &start); clock_gettime(CLOCK_MONOTONIC, &start);
mpz_init_set_ui(a, 1); mpz_init_set_ui(f1, 1);
mpz_init_set_ui(b, 1); mpz_init_set_ui(f2, 1);
mpz_init(fn);
i = 2; i = 2;
while(1) while(1)
{ {
mpz_add(a, a, b); /* Use the GMP Library to calculate the Fibonacci numbers.*/
mpz_add(fn, f1, f2);
i++; i++;
if((size = mpz_sizeinbase(a, 10)) == 1000) /* The function mpz_sizeinbase gives the number of digits of
* the number in the given base, but the result is either exact
* or one too big. To check the exact size, the number is
* converted to string and the strlen function is used.*/
if((size = mpz_sizeinbase(fn, 10)) >= 1000)
{ {
if((num = (char *)malloc((2+size)*sizeof(char))) == NULL) if((num = (char *)malloc((2+size)*sizeof(char))) == NULL)
{ {
fprintf(stderr, "Error while allocating memory\n"); fprintf(stderr, "Error while allocating memory\n");
return 1; return 1;
} }
gmp_sprintf(num, "%Zd", a); gmp_sprintf(num, "%Zd", fn);
size = strlen(num); size = strlen(num);
free(num); free(num);
if(size == 1000) if(size == 1000)
@ -41,27 +68,11 @@ int main(int argc, char **argv)
} }
} }
mpz_add(b, a, b); mpz_set(f1, f2);
i++; mpz_set(f2, fn);
if((size = mpz_sizeinbase(b, 10)) == 1000)
{
if((num = (char *)malloc((2+size)*sizeof(char))) == NULL)
{
fprintf(stderr, "Error while allocating memory\n");
return 1;
}
gmp_sprintf(num, "%Zd", b);
size = strlen(num);
free(num);
if(size == 1000)
{
break;
}
}
} }
mpz_clears(a, b, NULL); mpz_clears(f1, f2, fn, NULL);
clock_gettime(CLOCK_MONOTONIC, &end); clock_gettime(CLOCK_MONOTONIC, &end);

View File

@ -50,7 +50,7 @@ int is_palindrome(int num, int base)
/* Start with reverse=0, get the rightmost digit of the number using /* Start with reverse=0, get the rightmost digit of the number using
* modulo operation (num modulo base), add it to reverse. Remove the * modulo operation (num modulo base), add it to reverse. Remove the
* rightmost digit dividing num by the base, shift the reverse left * rightmost digit from num dividing num by the base, shift the reverse left
* multiplying by the base, repeat until all digits have been inserted * multiplying by the base, repeat until all digits have been inserted
* in reverse order.*/ * in reverse order.*/
while(tmp > 0) while(tmp > 0)
@ -192,8 +192,12 @@ int find_max_path(int **triang, int n)
{ {
int i, j; int i, j;
/* Start from the second to last row and go up.*/
for(i = n - 2; i >= 0; i--) 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++) for(j = 0; j <= i; j++)
{ {
if(triang[i+1][j] > triang[i+1][j+1]) if(triang[i+1][j] > triang[i+1][j+1])
@ -206,11 +210,40 @@ int find_max_path(int **triang, int n)
return triang[0][0]; 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)) void insertion_sort(void **array, int l, int r, int (*cmp)(void *lv, void *rv))
{ {
int i, j; int i, j;
void *tmp; void *tmp;
/* After this cycle the smallest element will be in the first position of the array.*/
for(i = r; i > l; i--) for(i = r; i > l; i--)
{ {
if(cmp(array[i], array[i-1]) < 0) if(cmp(array[i], array[i-1]) < 0)
@ -220,6 +253,9 @@ void insertion_sort(void **array, int l, int r, int (*cmp)(void *lv, void *rv))
array[i-1] = tmp; 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++) for(i = l + 2; i <= r; i++)
{ {
tmp = array[i]; tmp = array[i];
@ -240,11 +276,15 @@ int partition(void **array, int l, int r, int (*cmp)(void *lv, void *rv))
int i = l -1, j = r; int i = l -1, j = r;
void *pivot, *tmp; void *pivot, *tmp;
/* Arbitrarily selecting the rightmost element as pivot.*/
pivot = array[r]; pivot = array[r];
while(1) while(1)
{ {
/* From the left, loop until an element greater than the pivot is found.*/
while(cmp(array[++i], pivot) < 0); 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) while(cmp(array[--j], pivot) > 0)
{ {
if(j == l) if(j == l)
@ -253,16 +293,22 @@ int partition(void **array, int l, int r, int (*cmp)(void *lv, void *rv))
} }
} }
/* 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) if(j <= i)
{ {
break; break;
} }
/* If j>i, swap array[i] and array[j].*/
tmp = array[i]; tmp = array[i];
array[i] = array[j]; array[i] = array[j];
array[j] = tmp; 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]; tmp = array[i];
array[i] = array[r]; array[i] = array[r];
array[r] = tmp; array[r] = tmp;
@ -274,12 +320,14 @@ void quick_sort(void **array, int l, int r, int (*cmp)(void *lv, void *rv))
{ {
int i; int i;
if(r - l <= 10) /* 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); insertion_sort(array, l, r, cmp);
return; return;
} }
/* Partition the array and recursively run quick_sort on the two partitions.*/
i = partition(array, l, r, cmp); i = partition(array, l, r, cmp);
quick_sort(array, l, i-1, cmp); quick_sort(array, l, i-1, cmp);
quick_sort(array, i+1, r, cmp); quick_sort(array, i+1, r, cmp);

View File

@ -9,6 +9,7 @@ long int lcmm(long int *values, int n);
int *sieve(int n); int *sieve(int n);
int count_divisors(int n); int count_divisors(int n);
int find_max_path(int **triang, int n); int find_max_path(int **triang, int n);
int sum_of_divisors(int n);
void insertion_sort(void **array, int l, int r, int (*cmp)(void *lv, void *rv)); void insertion_sort(void **array, int l, int r, int (*cmp)(void *lv, void *rv));
void quick_sort(void **array, int l, int r, int (*cmp)(void *lv, void *rv)); void quick_sort(void **array, int l, int r, int (*cmp)(void *lv, void *rv));
int is_pandigital(int value, int n); int is_pandigital(int value, int n);

View File

@ -1,21 +1,9 @@
#!/usr/bin/python3 #!/usr/bin/python3
from timeit import default_timer from timeit import default_timer
from projecteuler import find_max_path
def sum_triangle(triang, n, i, j, sum_):
global max_
if i == n:
if sum_ > max_:
max_ = sum_
return max_
sum_triangle(triang, n, i+1, j, sum_+triang[i][j])
sum_triangle(triang, n, i+1, j+1, sum_+triang[i][j])
def main(): def main():
global max_
start = default_timer() start = default_timer()
try: try:
@ -36,8 +24,7 @@ def main():
for i in range(l): for i in range(l):
triang[i] = list(map(int, triang[i])) triang[i] = list(map(int, triang[i]))
max_ = 0 max_ = find_max_path(triang, 15)
sum_triangle(triang, 15, 0, 0, 0)
end = default_timer() end = default_timer()

View File

@ -80,6 +80,16 @@ def count_divisors(n):
return count return count
def find_max_path(triang, n):
for i in range(n-2, -1, -1):
for j in range(0, i+1):
if triang[i+1][j] > triang[i+1][j+1]:
triang[i][j] = triang[i][j] + triang[i+1][j]
else:
triang[i][j] = triang[i][j] + triang[i+1][j+1]
return triang[0][0]
def is_pandigital(value, n): def is_pandigital(value, n):
i = 0 i = 0
digits = zeros(n + 1, int) digits = zeros(n + 1, int)