Skip to content

Commit

Permalink
Solve problems 6, 9, 11, 14, 15, 34, 76 in C++
Browse files Browse the repository at this point in the history
  • Loading branch information
LivInTheLookingGlass committed Jul 22, 2024
1 parent cf48976 commit e463195
Show file tree
Hide file tree
Showing 21 changed files with 731 additions and 16 deletions.
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ LivInTheLookingGlass’s Project Euler solutions
| | ``clang``, ``msvc``, | | |
| | |br| ``pcc``, ``tcc`` | | |
+------------+-------------------------+--------+-------------------+
| C++ | C++98+ in |br| | 3 | |Cpi| |
| C++ | C++98+ in |br| | 10 | |Cpi| |
| | ``gcc``, ``clang`` |br| | | |
| | C++14+ in ``msvc`` | | |
+------------+-------------------------+--------+-------------------+
Expand Down
8 changes: 0 additions & 8 deletions cplusplus/include/macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,6 @@

// helper macro function section

#ifndef max
#define max(a, b) (((a) > (b)) ? (a) : (b))
#endif

#ifndef min
#define min(a, b) (((a) < (b)) ? (a) : (b))
#endif

#if !(CL_COMPILER)
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
Expand Down
88 changes: 88 additions & 0 deletions cplusplus/include/math.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#ifndef EULER_MATH_H
#define EULER_MATH_H

#include "macros.h"
#include <math.h>
#include <stdlib.h>
#include <stdint.h>

using namespace std;

uintmax_t factorial(unsigned int n);
inline uintmax_t factorial(unsigned int n) {
// note that this function only works for numbers smaller than MAX_FACTORIAL_64
if ((sizeof(uintmax_t) == 8 && n > MAX_FACTORIAL_64) || (sizeof(uintmax_t) == 16 && n > MAX_FACTORIAL_128))
return -1;
uintmax_t ret = 1;
for (unsigned int i = 2; i <= n; ++i) {
ret *= i;
}
return ret;
}

uintmax_t n_choose_r(unsigned int n, unsigned int r) {
// function returns -1 if it overflows
if ((sizeof(uintmax_t) == 8 && n <= MAX_FACTORIAL_64) || (sizeof(uintmax_t) == 16 && n <= MAX_FACTORIAL_128)) {
// fast path if small enough
return factorial(n) / factorial(r) / factorial(n-r);
}
// slow path for larger numbers
int *factors;
uintmax_t answer, tmp;
unsigned int i, j;
factors = (int *) malloc(sizeof(int) * (n + 1));
// collect factors of final number
for (i = 2; i <= n; i++) {
factors[i] = 1;
}
// negative factor values indicate need to divide
for (i = 2; i <= r; i++) {
factors[i] -= 1;
}
for (i = 2; i <= n - r; i++) {
factors[i] -= 1;
}
// this loop reduces to prime factors only
for (i = n; i > 1; i--) {
for (j = 2; j < i; j++) {
if (i % j == 0) {
factors[j] += factors[i];
factors[i / j] += factors[i];
factors[i] = 0;
break;
}
}
}
i = j = 2;
answer = 1;
while (i <= n) {
while (factors[i] > 0) {
tmp = answer;
answer *= i;
while (answer < tmp && j <= n) {
while (factors[j] < 0) {
tmp /= j;
factors[j]++;
}
j++;
answer = tmp * i;
}
if (answer < tmp) {
return -1; // this indicates an overflow
}
factors[i]--;
}
i++;
}
while (j <= n) {
while (factors[j] < 0) {
answer /= j;
factors[j]++;
}
j++;
}
free(factors);
return answer;
}

#endif
40 changes: 40 additions & 0 deletions cplusplus/p0006.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
Project Euler Problem 6
I know there is a closed form solution to sum of squares, but I didn't want to
cheat and look it up. I was able to remember the closed form formula for sum of
natural numbers, though, so this is still pretty fast.
Problem:
The sum of the squares of the first ten natural numbers is,
1**2 + 2**2 + ... + 10**2 = 385
The square of the sum of the first ten natural numbers is,
(1 + 2 + ... + 10)**2 = 55**2 = 3025
Hence the difference between the sum of the squares of the first ten natural
numbers and the square of the sum is 3025 − 385 = 2640.
Find the difference between the sum of the squares of the first one hundred
natural numbers and the square of the sum.
*/
#ifndef EULER_P0006
#define EULER_P0006
#include <iostream>

unsigned long long p0006() {
unsigned long long sum = 100 * 101 / 2, sum_of_squares = 0;
for (unsigned long long i = 1; i < 101; i++) {
sum_of_squares += i * i;
}
return sum * sum - sum_of_squares;
}

#ifndef UNITY_END
int main(int argc, char const *argv[]) {
std::cout << p0006() << std::endl;
return 0;
}
#endif
#endif
40 changes: 40 additions & 0 deletions cplusplus/p0009.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
Project Euler Problem 9
This was fairly short to code, but it took me a minute to figure out how to deal with the lack of multi-loop breaking
Problem:
A Pythagorean triplet is a set of three natural numbers, a < b < c, for which,
a2 + b2 = c2
For example, 32 + 42 = 9 + 16 = 25 = 52.
There exists exactly one Pythagorean triplet for which a + b + c = 1000.
Find the product abc.
*/
#ifndef EULER_P0009
#define EULER_P0009
#include <iostream>

unsigned long long p0009() {
unsigned long long answer = 0;
for (unsigned int c = 3; !answer && c < 1000; c++) {
for (unsigned int b = 2; b < c; b++) {
unsigned int a = 1000 - c - b;
if (a < b && a*a + b*b == c*c) {
answer = (unsigned long long) a * b * c;
break;
}
}
}
return answer;
}

#ifndef UNITY_END
int main(int argc, char const *argv[]) {
std::cout << p0009() << std::endl;
return 0;
}
#endif
#endif
93 changes: 93 additions & 0 deletions cplusplus/p0011.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
Project Euler Problem 11
Problem:
In the 20×20 grid below, four numbers along a diagonal line have been marked in red.
08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08
49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00
81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65
52 70 95 23 04 60 11 42 69 24 68 56 01 32 56 71 37 02 36 91
22 31 16 71 51 67 63 89 41 92 36 54 22 40 40 28 66 33 13 80
24 47 32 60 99 03 45 02 44 75 33 53 78 36 84 20 35 17 12 50
32 98 81 28 64 23 67 10 26 38 40 67 59 54 70 66 18 38 64 70
67 26 20 68 02 62 12 20 95 63 94 39 63 08 40 91 66 49 94 21
24 55 58 05 66 73 99 26 97 17 78 78 96 83 14 88 34 89 63 72
21 36 23 09 75 00 76 44 20 45 35 14 00 61 33 97 34 31 33 95
78 17 53 28 22 75 31 67 15 94 03 80 04 62 16 14 09 53 56 92
16 39 05 42 96 35 31 47 55 58 88 24 00 17 54 24 36 29 85 57
86 56 00 48 35 71 89 07 05 44 44 37 44 60 21 58 51 54 17 58
19 80 81 68 05 94 47 69 28 73 92 13 86 52 17 77 04 89 55 40
04 52 08 83 97 35 99 16 07 97 57 32 16 26 26 79 33 27 98 66
88 36 68 87 57 62 20 72 03 46 33 67 46 55 12 32 63 93 53 69
04 42 16 73 38 25 39 11 24 94 72 18 08 46 29 32 40 62 76 36
20 69 36 41 72 30 23 88 34 62 99 69 82 67 59 85 74 04 36 16
20 73 35 29 78 31 90 01 74 31 49 71 48 86 81 16 23 57 05 54
01 70 54 71 83 51 54 69 16 92 33 48 61 43 52 01 89 19 67 48
The product of these numbers is 26 × 63 × 78 × 14 = 1788696.
What is the greatest product of four adjacent numbers in the same direction (up, down, left, right, or diagonally) in
the 20×20 grid?
*/
#ifndef EULER_P0011
#define EULER_P0011
#include <iostream>

static const unsigned char grid[20][20] = {
{ 8, 2, 22, 97, 38, 15, 0, 40, 0, 75, 4, 5, 7, 78, 52, 12, 50, 77, 91, 8},
{49, 49, 99, 40, 17, 81, 18, 57, 60, 87, 17, 40, 98, 43, 69, 48, 4, 56, 62, 0},
{81, 49, 31, 73, 55, 79, 14, 29, 93, 71, 40, 67, 53, 88, 30, 3, 49, 13, 36, 65},
{52, 70, 95, 23, 4, 60, 11, 42, 69, 24, 68, 56, 1, 32, 56, 71, 37, 2, 36, 91},
{22, 31, 16, 71, 51, 67, 63, 89, 41, 92, 36, 54, 22, 40, 40, 28, 66, 33, 13, 80},
{24, 47, 32, 60, 99, 03, 45, 2, 44, 75, 33, 53, 78, 36, 84, 20, 35, 17, 12, 50},
{32, 98, 81, 28, 64, 23, 67, 10, 26, 38, 40, 67, 59, 54, 70, 66, 18, 38, 64, 70},
{67, 26, 20, 68, 2, 62, 12, 20, 95, 63, 94, 39, 63, 8, 40, 91, 66, 49, 94, 21},
{24, 55, 58, 5, 66, 73, 99, 26, 97, 17, 78, 78, 96, 83, 14, 88, 34, 89, 63, 72},
{21, 36, 23, 9, 75, 0, 76, 44, 20, 45, 35, 14, 0, 61, 33, 97, 34, 31, 33, 95},
{78, 17, 53, 28, 22, 75, 31, 67, 15, 94, 3, 80, 4, 62, 16, 14, 9, 53, 56, 92},
{16, 39, 5, 42, 96, 35, 31, 47, 55, 58, 88, 24, 0, 17, 54, 24, 36, 29, 85, 57},
{86, 56, 0, 48, 35, 71, 89, 7, 5, 44, 44, 37, 44, 60, 21, 58, 51, 54, 17, 58},
{19, 80, 81, 68, 5, 94, 47, 69, 28, 73, 92, 13, 86, 52, 17, 77, 4, 89, 55, 40},
{ 4, 52, 8, 83, 97, 35, 99, 16, 7, 97, 57, 32, 16, 26, 26, 79, 33, 27, 98, 66},
{88, 36, 68, 87, 57, 62, 20, 72, 3, 46, 33, 67, 46, 55, 12, 32, 63, 93, 53, 69},
{ 4, 42, 16, 73, 38, 25, 39, 11, 24, 94, 72, 18, 8, 46, 29, 32, 40, 62, 76, 36},
{20, 69, 36, 41, 72, 30, 23, 88, 34, 62, 99, 69, 82, 67, 59, 85, 74, 04, 36, 16},
{20, 73, 35, 29, 78, 31, 90, 1, 74, 31, 49, 71, 48, 86, 81, 16, 23, 57, 5, 54},
{ 1, 70, 54, 71, 83, 51, 54, 69, 16, 92, 33, 48, 61, 43, 52, 1, 89, 19, 67, 48}
};

unsigned long long p0011() {
unsigned long answer = 0, tmp;
unsigned char i, j;
for (i = 0; i < 20; i++) {
for (j = 0; j < 17; j++) {
// horizontal section
tmp = grid[i][j] * grid[i][j + 1] * grid[i][j + 2] * grid[i][j + 3];
answer = std::max(answer, tmp);
// vertical section
tmp = grid[j][i] * grid[j + 1][i] * grid[j + 2][i] * grid[j + 3][i];
answer = std::max(answer, tmp);
}
}
for (i = 0; i < 17; i++) {
for (j = 0; j < 17; j++) {
// right diagonal section
tmp = grid[i][j] * grid[i + 1][j + 1] * grid[i + 2][j + 2] * grid[i + 3][j + 3];
answer = std::max(answer, tmp);
// left diagonal section
tmp = grid[i][j + 3] * grid[i + 1][j + 2] * grid[i + 2][j + 1] * grid[i + 3][j];
answer = std::max(answer, tmp);
}
}
return answer;
}

#ifndef UNITY_END
int main(int argc, char const *argv[]) {
std::cout << p0011() << std::endl;
return 0;
}
#endif
#endif
66 changes: 66 additions & 0 deletions cplusplus/p0014.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
Project Euler Problem 14
This was easier to do in C++ than I would have thought
Problem:
The following iterative sequence is defined for the set of positive integers:
n → n/2 (n is even)
n → 3n + 1 (n is odd)
Using the rule above and starting with 13, we generate the following sequence:
13 → 40 → 20 → 10 → 5 → 16 → 8 → 4 → 2 → 1
It can be seen that this sequence (starting at 13 and finishing at 1) contains 10 terms. Although it has not been
proved yet (Collatz Problem), it is thought that all starting numbers finish at 1.
Which starting number, under one million, produces the longest chain?
NOTE: Once the chain starts the terms are allowed to go above one million.
*/
#ifndef EULER_P0014
#define EULER_P0014
#include <iostream>

#define CACHE_SIZE 1000000
static unsigned int collatz_len_cache[CACHE_SIZE] = {0, 1, 0};

unsigned int collatz_len(unsigned long long n);

unsigned int collatz_len(unsigned long long n) {
if (n < CACHE_SIZE && collatz_len_cache[n]) {
return collatz_len_cache[n];
}
unsigned int ret = 0;
if (n % 2) {
ret = 2 + collatz_len((3 * n + 1) / 2);
} else {
ret = 1 + collatz_len(n / 2);
}
if (n < CACHE_SIZE) {
collatz_len_cache[n] = ret;
}
return ret;
}

unsigned long long p0014() {
unsigned long long answer = 2, length = 2, tmp;
for (unsigned long long test = 3; test < 1000000; test++) {
tmp = collatz_len(test);
if (tmp > length) {
answer = test;
length = tmp;
}
}
return answer;
}

#ifndef UNITY_END
int main(int argc, char const *argv[]) {
std::cout << p0014() << std::endl;
return 0;
}
#endif
#endif
34 changes: 34 additions & 0 deletions cplusplus/p0015.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
Project Euler Problem 15
Turns out this is easy, if you think sideways a bit
You can only go down or right. If we say right=1, then you can only have 20 1s, since otherwise you go off the grid.
You also can't have fewer than 20 1s, since then you go off the grid the other way. This means you can look at it as a
bit string, and the number of 40-bit strings with 20 1s is 40c20.
Problem:
Starting in the top left corner of a 2×2 grid, and only being able to move to the right and down, there are exactly 6
routes to the bottom right corner.
How many such routes are there through a 20×20 grid?
*/
#ifndef EULER_P0015
#define EULER_P0015
#include <iostream>
#include "include/math.h"

#define lattice_paths(height, width) (n_choose_r(height + width, height))

unsigned long long p0015() {
return lattice_paths(20, 20);
}

#ifndef UNITY_END
int main(int argc, char const *argv[]) {
std::cout << p0015() << std::endl;
return 0;
}
#endif
#endif
Loading

0 comments on commit e463195

Please sign in to comment.