Improve problem 95 solution

This commit is contained in:
daniele 2019-10-02 12:47:03 +02:00
parent e7f8e6f633
commit 9e247f1624
Signed by: fuxino
GPG Key ID: 6FE25B4A3EE16FDA

View File

@ -16,56 +16,38 @@
#include <stdlib.h> #include <stdlib.h>
#include <math.h> #include <math.h>
#include <time.h> #include <time.h>
#include "projecteuler.h"
#define N 1000000 #define N 1000000
int sum_proper_divisors(int i); int sum_proper_divisors(int i);
int sociable_chain(int i, int start, int *min, int l); int sociable_chain(int i, int start, int *min, int l);
int chains[N] = {0};
/* Vector to save the current chain values. I started with a longer vector, /* Vector to save the current chain values. I started with a longer vector,
* but no chain is longer than 100 elements, so this is sufficient.*/ * but no chain is longer than 100 elements, so this is sufficient.*/
int c[100]; int c[100];
int divisors[N] = {0}; int divisors[N] = {0};
int *primes;
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
/* l_max starts from 3 because we're interested in chains of at least 3 elements.*/ int i, min = 0, min_tmp, length, l_max = 0;
int i, min = 0, min_tmp, length, l_max = 2;
double elapsed; double elapsed;
struct timespec start, end; struct timespec start, end;
clock_gettime(CLOCK_MONOTONIC, &start); clock_gettime(CLOCK_MONOTONIC, &start);
if((primes = sieve(N+1)) == NULL)
{
fprintf(stderr, "Error! Sieve function returned NULL\n");
return 1;
}
for(i = 4; i <= N; i++) for(i = 4; i <= N; i++)
{ {
/* Calculate the divisors of i, or retrieve the value if previously calculated. /* Calculate the divisors of i and save it. Ii is equal to the sum of its proper divisors,
* If i is equal to the sum of its proper divisors, the length of the chain is 1 * the length of the chain is 1 and we don't need to check it.*/
* (i.e. i is a perfect number.*/ if((divisors[i] = sum_proper_divisors(i)) == i)
if(divisors[i] == i || (divisors[i] = sum_proper_divisors(i)) == i)
{ {
length = 1; continue;
chains[i] = length;
} }
else if(!primes[i]) else
{ {
min_tmp = i; min_tmp = i;
length = sociable_chain(i, i, &min_tmp, 0); length = sociable_chain(i, i, &min_tmp, 0);
} }
/* If i is prime, 1 is its only proper divisor, so no amicable chain is possible.*/
else
{
length = -1;
chains[i] = length;
}
if(length > l_max) if(length > l_max)
{ {
@ -74,8 +56,6 @@ int main(int argc, char **argv)
} }
} }
free(primes);
clock_gettime(CLOCK_MONOTONIC, &end); clock_gettime(CLOCK_MONOTONIC, &end);
elapsed = (end.tv_sec - start.tv_sec) + (double)(end.tv_nsec - start.tv_nsec) / 1000000000; elapsed = (end.tv_sec - start.tv_sec) + (double)(end.tv_nsec - start.tv_nsec) / 1000000000;
@ -111,30 +91,23 @@ int sum_proper_divisors(int n)
return sum; return sum;
} }
/* Function to recursively find the length of the chain.*/
int sociable_chain(int i, int start, int *min, int l) int sociable_chain(int i, int start, int *min, int l)
{ {
int n; int n;
/* If we already calculated that the current value can't form a chain, /* Save current number in the chain.*/
* or has a chain starting from a different number, it can't form a c[l] = i;
* chain starting with the current number, so just return -1.*/
if(chains[i] != 0)
{
chains[start] = -1;
return -1;
}
/* If we reached a prime number, the chain will never return to the starting number.*/ /* If we reached 1, the chain will never return go anywhere.*/
if(primes[i]) if(i == 1)
{ {
chains[start] = -1;
return -1; return -1;
} }
/* Calculate the divisors of i, or retrieve the value if previously calculated.*/ /* Calculate the divisors of i, or retrieve the value if previously calculated.*/
if(divisors[i] != 0) if(divisors[i] != 0)
{ {
chains[start] = -1;
n = divisors[i]; n = divisors[i];
} }
else else
@ -143,34 +116,28 @@ int sociable_chain(int i, int start, int *min, int l)
divisors[i] = n; divisors[i] = n;
} }
/* If the next number in the chain is equal to the starting one, the chain is finished.*/
if(n == start)
{
chains[start] = l + 1;
return l + 1;
}
/* Save n, i.e. the next value in the chain, and check if it's equal
* to another value of the chain different from start. If it is, the
* chain is stuck in a loop that will not return to the starting number.*/
c[l] = n;
for(i = 0; i < l; i++)
{
if(n == c[i])
{
chains[start] = -1;
return -1;
}
}
/* We are looking for chain where no value is greater than 1000000.*/ /* We are looking for chain where no value is greater than 1000000.*/
if(n > N) if(n > N)
{ {
chains[start] = -1;
return -1; return -1;
} }
/* If the next number in the chain is equal to the starting one, the chain is finished.*/
if(n == start)
{
return l + 1;
}
/* Check if n is equal to another value of the chain different from start. If it is, the
* chain is stuck in a loop that will not return to the starting number.*/
for(i = l; i > 0; i--)
{
if(n == c[i])
{
return -1;
}
}
/* If the next value is smaller than the minimum value of the chain, /* If the next value is smaller than the minimum value of the chain,
* update the minimum.*/ * update the minimum.*/
if(n < *min) if(n < *min)