Improve problem 95 solution
This commit is contained in:
parent
e7f8e6f633
commit
9e247f1624
87
C/p095.c
87
C/p095.c
@ -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)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user