198 lines
5.9 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* Triangle, square, pentagonal, hexagonal, heptagonal, and octagonal numbers are all figurate (polygonal) numbers and are generated
* by the following formulae:
*
* Triangle P3,n=n(n+1)/2 1, 3, 6, 10, 15, ...
* Square P4,n=n2 1, 4, 9, 16, 25, ...
* Pentagonal P5,n=n(3n1)/2 1, 5, 12, 22, 35, ...
* Hexagonal P6,n=n(2n1) 1, 6, 15, 28, 45, ...
* Heptagonal P7,n=n(5n3)/2 1, 7, 18, 34, 55, ...
* Octagonal P8,n=n(3n2) 1, 8, 21, 40, 65, ...
*
* The ordered set of three 4-digit numbers: 8128, 2882, 8281, has three interesting properties.
*
* The set is cyclic, in that the last two digits of each number is the first two digits of the next number (including the last number with the first).
* Each polygonal type: triangle (P3,127=8128), square (P4,91=8281), and pentagonal (P5,44=2882), is represented by a different number in the set.
* This is the only set of 4-digit numbers with this property.
*
* Find the sum of the only ordered set of six cyclic 4-digit numbers for which each polygonal type: triangle, square, pentagonal,
* hexagonal, heptagonal, and octagonal, is represented by a different number in the set.*/
#define _POSIX_C_SOURCE 199309L
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int find_set(int step, int *sum);
int polygonal[6][10000] = {0};
int chain[6], flags[6] = {0};
int main(int argc, char **argv)
{
int i, n, sum = 0;
double elapsed;
struct timespec start, end;
clock_gettime(CLOCK_MONOTONIC, &start);
i = 1;
n = 1;
/* Generate all triangle numbers smaller than 10000*/
do
{
polygonal[0][n] = 1;
i++;
n = i * (i + 1) / 2;
} while(n < 10000);
i = 1;
n = 1;
/* Generate all square numbers smaller than 10000.*/
do
{
polygonal[1][n] = 1;
i++;
n = i * i;
} while(n < 10000);
i = 1;
n = 1;
/* Generate all pentagonal numbers smaller than 10000.*/
do
{
polygonal[2][n] = 1;
i++;
n = i * (3 * i - 1) / 2;
} while(n < 10000);
i = 1;
n = 1;
/* Generate all hexagonal numbers smaller than 10000.*/
do
{
polygonal[3][n] = 1;
i++;
n = i * (2 * i - 1);
} while(n < 10000);
i = 1;
n = 1;
/* Generate all heptagonal numbers smaller than 10000.*/
do
{
polygonal[4][n] = 1;
i++;
n = i * (5 * i - 3) / 2;
} while(n < 10000);
i = 1;
n = 1;
/* Generate all octagonal numbers smaller than 10000.*/
do
{
polygonal[5][n] = 1;
i++;
n = i * (3 * i - 2);
} while(n < 10000);
/* Find the requested set of numbers.*/
if(find_set(0, &sum) == 0)
{
printf("Set not found\n");
}
clock_gettime(CLOCK_MONOTONIC, &end);
elapsed = (end.tv_sec - start.tv_sec) + (double)(end.tv_nsec - start.tv_nsec) / 1000000000;
printf("Project Euler, Problem 61\n");
printf("Answer: %d\n", sum);
printf("Elapsed time: %.9lf seconds\n", elapsed);
return 0;
}
/* Recursive function to find the required set. It finds a polygonal number,
* check if it can be part of the chain, then use recursion to find the next
* number. If a solution can't be found with the current numbers, it uses
* backtracking and tries the next polygonal number.*/
int find_set(int step, int *sum)
{
int i, j;
/* Use one polygonal number per type, starting from triangular.*/
for(i = 0; i < 6; i++)
{
/* If the current type has not been used yet, try it.*/
if(!flags[i])
{
/* Set a flag to record that the current polygonal type has been used.*/
flags[i] = 1;
/* Start from 1010 because numbers finishing with 00, 01, ..., 09 can't
* be part of the chain.*/
for(j = 1010; j < 10000; j++)
{
/* If the number doesn't finish with 00, 01, ..., 09 and is poligonal,
* try adding it to the chain and add its value to the total sum.*/
if(j % 100 > 9 && polygonal[i][j])
{
/* If it's the first number, just add it as first step in the chain.*/
if(step == 0)
{
chain[step] = j;
*sum += j;
/* Recursively try to add other numbers to the chain. If a solution
* is found, return 1.*/
if(find_set(step+1, sum))
{
return 1;
}
/* If a solution was not found, backtrack, subtracting the value of
* the number from the total.*/
*sum -= j;
}
/* If this is the last step and the current number can be added to the chain,
* add it, update the sum and return 1. A solution has been found.*/
else if(step == 5 && j % 100 == chain[0] / 100 && j / 100 == chain[step-1] % 100)
{
chain[step] = j;
*sum += j;
return 1;
}
/* For every other step, add the number to the chain if possible, then recursively
* try to add other numbers.*/
else if(step < 5 && j / 100 == chain[step-1] % 100)
{
chain[step] = j;
*sum += j;
if(find_set(step+1, sum))
{
return 1;
}
/* If a solution was not found, backtrack.*/
*sum -= j;
}
}
}
/* Remove the flag for the current polygonal type.*/
flags[i] = 0;
}
}
return 0;
}