Improve solutions for problems 18, 24 and 25
This commit is contained in:
parent
593d52144d
commit
b4c85f8f4a
1
C/p018.c
1
C/p018.c
@ -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
136
C/p024.c
@ -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);
|
||||||
}
|
}
|
||||||
|
61
C/p025.c
61
C/p025.c
@ -1,3 +1,24 @@
|
|||||||
|
/* The Fibonacci sequence is defined by the recurrence relation:
|
||||||
|
*
|
||||||
|
* Fn = Fn−1 + Fn−2, 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);
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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()
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user