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);
/* Use function implemented in projecteuler.c to find the maximum path.*/
max = find_max_path(triang, 15);
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 <stdlib.h>
#include <time.h>
#include "projecteuler.h"
void next_perm(int *perm, int n);
void swap(int *vet, int i, int j);
void sort(int *vet, int i, int n);
void next_perm(int **perm, int n);
void swap(int **vet, int i, int j);
int compare(void *a, void *b);
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;
struct timespec start, end;
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++)
{
/* Function that generates permutations in lexicographic order.
* Finish when the 1000000th is found.*/
next_perm(perm, 10);
}
for(i = 0; i < 10; i++)
{
res[i] = *perm[i];
free(perm[i]);
}
free(perm);
clock_gettime(CLOCK_MONOTONIC, &end);
printf("Project Euler, Problem 24\n");
@ -26,7 +61,7 @@ int main(int argc, char **argv)
for(i = 0; i < 10; i++)
{
printf("%d", perm[i]);
printf("%d", res[i]);
}
printf("\n");
@ -38,61 +73,56 @@ int main(int argc, char **argv)
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;
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;
int *tmp;
tmp = vet[i];
vet[i] = vet[j];
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++)
{
tmp=vet[a];
b=a-1;
while(b>=i && vet[b]>tmp)
{
vet[b+1]=vet[b];
b--;
}
vet[b+1]=tmp;
}
n1 = (int *)a;
n2 = (int *)b;
return *n1 - *n2;
}
/* Implements SEPA (Simple, Efficient Permutation Algorithm)
* to find the next permutation.*/
void next_perm(int **perm, int n)
{
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 <stdlib.h>
#include <string.h>
@ -9,30 +30,36 @@ int main(int argc, char **argv)
int i;
double elapsed;
struct timespec start, end;
mpz_t a, b;
mpz_t f1, f2, fn;
char *num;
size_t size;
clock_gettime(CLOCK_MONOTONIC, &start);
mpz_init_set_ui(a, 1);
mpz_init_set_ui(b, 1);
mpz_init_set_ui(f1, 1);
mpz_init_set_ui(f2, 1);
mpz_init(fn);
i = 2;
while(1)
{
mpz_add(a, a, b);
/* Use the GMP Library to calculate the Fibonacci numbers.*/
mpz_add(fn, f1, f2);
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)
{
fprintf(stderr, "Error while allocating memory\n");
return 1;
}
gmp_sprintf(num, "%Zd", a);
gmp_sprintf(num, "%Zd", fn);
size = strlen(num);
free(num);
if(size == 1000)
@ -41,27 +68,11 @@ int main(int argc, char **argv)
}
}
mpz_add(b, a, b);
i++;
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_set(f1, f2);
mpz_set(f2, fn);
}
mpz_clears(a, b, NULL);
mpz_clears(f1, f2, fn, NULL);
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
* 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
* in reverse order.*/
while(tmp > 0)
@ -192,8 +192,12 @@ 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])
@ -206,11 +210,40 @@ int find_max_path(int **triang, int n)
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)
@ -220,6 +253,9 @@ void insertion_sort(void **array, int l, int r, int (*cmp)(void *lv, void *rv))
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];
@ -239,12 +275,16 @@ 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)
@ -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)
{
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;
@ -273,13 +319,15 @@ int partition(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 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);
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);

View File

@ -9,6 +9,7 @@ long int lcmm(long int *values, int n);
int *sieve(int n);
int count_divisors(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 quick_sort(void **array, int l, int r, int (*cmp)(void *lv, void *rv));
int is_pandigital(int value, int n);

View File

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

View File

@ -80,6 +80,16 @@ def count_divisors(n):
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):
i = 0
digits = zeros(n + 1, int)