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);
|
||||
|
||||
/* 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
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 <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);
|
||||
}
|
||||
|
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 <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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user