From a82d27069165e894f85d826032df44b772e22d2f Mon Sep 17 00:00:00 2001 From: Daniele Fucini Date: Thu, 26 Sep 2019 10:23:01 +0200 Subject: [PATCH] Improve solution for problem 43 --- C/p043.c | 104 ++++++++++++++++++++++++++++------------------- C/projecteuler.c | 60 +++++++++++++++++++++++---- C/projecteuler.h | 2 + 3 files changed, 115 insertions(+), 51 deletions(-) diff --git a/C/p043.c b/C/p043.c index febb0ba..784fcf4 100644 --- a/C/p043.c +++ b/C/p043.c @@ -1,22 +1,62 @@ +/* The number, 1406357289, is a 0 to 9 pandigital number because it is made up of each of the digits 0 to 9 in some order, but it also has a + * rather interesting sub-string divisibility property. + * + * Let d1 be the 1st digit, d2 be the 2nd digit, and so on. In this way, we note the following: + * + * d2d3d4=406 is divisible by 2 + * d3d4d5=063 is divisible by 3 + * d4d5d6=635 is divisible by 5 + * d5d6d7=357 is divisible by 7 + * d6d7d8=572 is divisible by 11 + * d7d8d9=728 is divisible by 13 + * d8d9d10=289 is divisible by 17 + * + * Find the sum of all 0 to 9 pandigital numbers with this property.*/ + #include #include #include +#include "projecteuler.h" -void permute(int *v, int i, int n); -void swap(int *a, int *b); -int has_property(int *v); - -long int sum = 0; +int compare(void *a, void *b); +int has_property(int **n); int main(int argc, char **argv) { - int n[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + int i; + int **n; + long int sum = 0; double elapsed; struct timespec start, end; clock_gettime(CLOCK_MONOTONIC, &start); - permute(n, 0, 9); + if((n = (int **)malloc(10*sizeof(int *))) == NULL) + { + fprintf(stderr, "Error while allocating memory\n"); + return 1; + } + + for(i = 0; i < 10; i++) + { + if((n[i] = (int *)malloc(sizeof(int))) == NULL) + { + fprintf(stderr, "Error while allocating memory\n"); + return 1; + } + *n[i] = i; + } + + /* Find the next permutation and check if it has the required property. + * Repeat until all the permutations have been found.*/ + while(next_permutation((void **)n, 10, compare) != -1) + { + if(has_property(n)) + { + sum += *n[0] * 1e9 + *n[1] * 1e8 + *n[2] * 1e7 + *n[3] * 1e6 + *n[4] * 1e5 + + *n[5] * 1e4 + *n[6] * 1e3 + *n[7] * 1e2 + *n[8] * 1e1 + *n[9]; + } + } clock_gettime(CLOCK_MONOTONIC, &end); @@ -30,84 +70,64 @@ int main(int argc, char **argv) return 0; } -void permute(int *v, int i, int n) +int compare(void *a, void *b) { - int j; + int *n1, *n2; - if(i == n) - { - if(has_property(v)) - { - sum += v[0] * 1e9 + v[1] * 1e8 + v[2] * 1e7 + v[3] * 1e6 + v[4] * 1e5 + v[5] * 1e4 + v[6] * 1e3 + v[7] * 1e2 + v[8] * 1e1 + v[9]; - } - } - else - { - for(j = i; j <= n; j++) - { - swap((v+i), (v+j)); - permute(v, i+1, n); - swap((v+i), (v+j)); - } - } + n1 = (int *)a; + n2 = (int *)b; + + return *n1 - *n2; } -void swap(int *a, int *b) -{ - int tmp; - - tmp = *a; - *a = *b; - *b = tmp; -} - -int has_property(int *v) +/* Function to check if the value has the desired property.*/ +int has_property(int **n) { long int value; - value = v[1] * 100 + v[2] * 10 + v[3]; + value = *n[1] * 100 + *n[2] * 10 + *n[3]; if(value % 2 != 0) { return 0; } - value = v[2] * 100 + v[3] * 10 + v[4]; + value = *n[2] * 100 + *n[3] * 10 + *n[4]; if(value % 3 != 0) { return 0; } - value = v[3] * 100 + v[4] * 10 + v[5]; + value = *n[3] * 100 + *n[4] * 10 + *n[5]; if(value % 5 != 0) { return 0; } - value = v[4] * 100 + v[5] * 10 + v[6]; + value = *n[4] * 100 + *n[5] * 10 + *n[6]; if(value % 7 != 0) { return 0; } - value = v[5] * 100 + v[6] * 10 + v[7]; + value = *n[5] * 100 + *n[6] * 10 + *n[7]; if(value % 11 != 0) { return 0; } - value = v[6] * 100 + v[7] * 10 + v[8]; + value = *n[6] * 100 + *n[7] * 10 + *n[8]; if(value %13 != 0) { return 0; } - value = v[7] * 100 + v[8] * 10 + v[9]; + value = *n[7] * 100 + *n[8] * 10 + *n[9]; if(value % 17 != 0) { diff --git a/C/projecteuler.c b/C/projecteuler.c index 9a72fc3..2467c96 100644 --- a/C/projecteuler.c +++ b/C/projecteuler.c @@ -266,6 +266,15 @@ int sum_of_divisors(int n) return sum; } +void swap(void **array, int i, int j) +{ + void *tmp; + + tmp = array[i]; + array[i] = array[j]; + array[j] = tmp; +} + void insertion_sort(void **array, int l, int r, int (*cmp)(void *lv, void *rv)) { int i, j; @@ -276,9 +285,7 @@ void insertion_sort(void **array, int l, int r, int (*cmp)(void *lv, void *rv)) { if(cmp(array[i], array[i-1]) < 0) { - tmp = array[i]; - array[i] = array[i-1]; - array[i-1] = tmp; + swap(array, i, i-1); } } @@ -329,17 +336,13 @@ int partition(void **array, int l, int r, int (*cmp)(void *lv, void *rv)) } /* If j>i, swap array[i] and array[j].*/ - tmp = array[i]; - array[i] = array[j]; - array[j] = tmp; + swap(array, i, j); } /* 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; + swap(array, i, r); return i; } @@ -361,6 +364,43 @@ void quick_sort(void **array, int l, int r, int (*cmp)(void *lv, void *rv)) quick_sort(array, i+1, r, cmp); } +/* Implements SEPA (Simple, Efficient Permutation Algorithm) + * to find the next permutation.*/ +int next_permutation(void **perm, int n, int (*cmp)(void *a, void *b)) +{ + 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(cmp(perm[i], 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 -1; + } + + /* 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 && cmp(perm[i], 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(perm, key+1, n-1, cmp); + + return 0; +} + int is_pandigital(int value, int n) { int *digits; @@ -413,6 +453,8 @@ int is_pentagonal(long int n) { double i; + /* A number n is pentagonal if p=(sqrt(24n+1)+1)/6 is an integer. + * In this case, n is the pth pentagonal number.*/ i = (sqrt(24*n+1) + 1) / 6; if(i == (int)i) diff --git a/C/projecteuler.h b/C/projecteuler.h index 35e8013..55260cb 100644 --- a/C/projecteuler.h +++ b/C/projecteuler.h @@ -13,8 +13,10 @@ int *sieve(int n); int count_divisors(int n); int find_max_path(int **triang, int n); int sum_of_divisors(int n); +void swap(void **vet, int i, int j); 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 next_permutation(void **perm, int n, int (*cmp)(void *a, void *b)); int is_pandigital(int value, int n); int is_pentagonal(long int n);