fix(curriculum): rework Project Euler 61 (#42397)

This commit is contained in:
gikf
2021-06-14 08:31:28 +02:00
committed by GitHub
parent c4cf53a742
commit 2613622ef0

View File

@ -11,36 +11,52 @@ dashedName: problem-61-cyclical-figurate-numbers
Triangle, square, pentagonal, hexagonal, heptagonal, and octagonal numbers are all figurate (polygonal) numbers and are generated by the following formulae:
| Type of Number | Formula | Sequence |
| -------------- | --------------------------------------------------------------------- | --------------------- |
| Triangle | P<sub>3</sub>,<var><sub>n</sub></var>=<var>n</var>(<var>n</var>+1)/2 | 1, 3, 6, 10, 15, ... |
| Square | P<sub>4</sub>,<var><sub>n</sub></var>=<var>n</var><sup>2</sup> | 1, 4, 9, 16, 25, ... |
| Pentagonal | P<sub>5</sub>,<var><sub>n</sub></var>=<var>n</var>(3<var>n</var>1)/2 | 1, 5, 12, 22, 35, ... |
| Hexagonal | P<sub>6</sub>,<var><sub>n</sub></var>=<var>n</var>(2<var>n</var>1) | 1, 6, 15, 28, 45, ... |
| Heptagonal | P<sub>7</sub>,<var><sub>n</sub></var>=<var>n</var>(5<var>n</var>3)/2 | 1, 7, 18, 34, 55, ... |
| Octagonal | P<sub>8</sub>,<var><sub>n</sub></var>=<var>n</var>(3<var>n</var>2) | 1, 8, 21, 40, 65, ... |
| -------------- | ---------------------------- | --------------------- |
| Triangle | $P_3(n) = \frac{n(n+1)}{2}$ | 1, 3, 6, 10, 15, ... |
| Square | $P_4(n) = n^2$ | 1, 4, 9, 16, 25, ... |
| Pentagonal | $P_5(n) = \frac{n(3n1)}2$ | 1, 5, 12, 22, 35, ... |
| Hexagonal | $P_6(n) = n(2n1)$ | 1, 6, 15, 28, 45, ... |
| Heptagonal | $P_7(n) = \frac{n(5n3)}{2}$ | 1, 7, 18, 34, 55, ... |
| Octagonal | $P_8(n) = n(3n2)$ | 1, 8, 21, 40, 65, ... |
The ordered set of three 4-digit numbers: 8128, 2882, 8281, has three interesting properties.
<ol>
<li>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).</li>
<li>Each polygonal type: triangle (P<sub>3,127</sub> = 8128), square (P<sub>4,91</sub> = 8281), and pentagonal (P<sub>5,44</sub> = 2882), is represented by a different number in the set.</li>
<li>This is the only set of 4-digit numbers with this property.</li>
</ol>
1. 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).
2. Each polygonal type: triangle ($P_3(127) = 8128$), square ($P_4(91) = 8281$), and pentagonal ($P_5(44) = 2882$), is represented by a different number in the set.
3. 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.
Find the sum of all numbers in ordered sets of `n` cyclic 4-digit numbers for which each of the $P_3$ to $P_{n + 2}$ polygonal types, is represented by a different number in the set.
# --hints--
`cyclicalFigurateNums()` should return a number.
`cyclicalFigurateNums(3)` should return a number.
```js
assert(typeof cyclicalFigurateNums() === 'number');
assert(typeof cyclicalFigurateNums(3) === 'number');
```
`cyclicalFigurateNums()` should return 28684.
`cyclicalFigurateNums(3)` should return `19291`.
```js
assert.strictEqual(cyclicalFigurateNums(), 28684);
assert.strictEqual(cyclicalFigurateNums(3), 19291);
```
`cyclicalFigurateNums(4)` should return `28684`.
```js
assert.strictEqual(cyclicalFigurateNums(4), 28684);
```
`cyclicalFigurateNums(5)` should return `76255`.
```js
assert.strictEqual(cyclicalFigurateNums(5), 76255);
```
`cyclicalFigurateNums(6)` should return `28684`.
```js
assert.strictEqual(cyclicalFigurateNums(6), 28684);
```
# --seed--
@ -48,16 +64,189 @@ assert.strictEqual(cyclicalFigurateNums(), 28684);
## --seed-contents--
```js
function cyclicalFigurateNums() {
function cyclicalFigurateNums(n) {
return true;
}
cyclicalFigurateNums();
cyclicalFigurateNums(3);
```
# --solutions--
```js
// solution required
function cyclicalFigurateNums(n) {
function getChains(chain, n, numberTypes, numsExcludingLastNeededType) {
if (chain.length === n) {
return [chain];
}
const nextNumbers = getNextNumbersInChain(
chain[chain.length - 1],
numsExcludingLastNeededType
);
const chains = [];
for (let j = 0; j < nextNumbers.length; j++) {
const nextNumber = nextNumbers[j];
if (chain.indexOf(nextNumber) === -1) {
const nextChain = [...chain, nextNumber];
chains.push(
...getChains(nextChain, n, numberTypes, numsExcludingLastNeededType)
);
}
}
return chains;
}
function getNextNumbersInChain(num, numsExcludingLastNeededType) {
const results = [];
const beginning = num % 100;
numsExcludingLastNeededType.forEach(number => {
if (Math.floor(number / 100) === beginning) {
results.push(number);
}
});
return results;
}
function fillNumberTypes(n, numberTypes, numsExcludingLastNeededType) {
const [, lastTypeCheck, lastTypeArr] = numberTypes[n - 1];
for (let i = 1000; i <= 9999; i++) {
for (let j = 0; j < n - 1; j++) {
const [, typeCheck, typeArr] = numberTypes[j];
if (typeCheck(i)) {
typeArr.push(i);
numsExcludingLastNeededType.add(i);
}
}
if (lastTypeCheck(i)) {
lastTypeArr.push(i);
}
}
}
function isCyclicalChain(chain, n, numberTypes) {
const numberTypesInChain = getNumberTypesInChain(chain, numberTypes);
if (!isChainAllowed(numberTypesInChain, n)) {
return false;
}
const isChainCyclic =
Math.floor(chain[0] / 100) === chain[chain.length - 1] % 100;
return isChainCyclic;
}
function getNumberTypesInChain(chain, numberTypes) {
const numbersInChain = {};
for (let i = 0; i < numberTypes.length; i++) {
const numberTypeName = numberTypes[i][0];
numbersInChain[numberTypeName] = [];
}
for (let i = 0; i < chain.length; i++) {
for (let j = 0; j < n; j++) {
const [typeName, , typeNumbers] = numberTypes[j];
const typeNumbersInChain = numbersInChain[typeName];
if (typeNumbers.indexOf(chain[i]) !== -1) {
typeNumbersInChain.push(chain[i]);
}
}
}
return numbersInChain;
}
function isChainAllowed(numberTypesInChain, n) {
for (let i = 0; i < n; i++) {
const typeName = numberTypes[i][0];
const isNumberWithTypeInChain = numberTypesInChain[typeName].length > 0;
if (!isNumberWithTypeInChain) {
return false;
}
for (let j = i + 1; j < n; j++) {
const otherTypeName = numberTypes[j][0];
if (
isNumberRepeatedAsOnlyNumberInTwoTypes(
numberTypesInChain[typeName],
numberTypesInChain[otherTypeName]
)
) {
return false;
}
}
}
return true;
}
function isNumberRepeatedAsOnlyNumberInTwoTypes(
typeNumbers,
otherTypeNumbers
) {
return (
typeNumbers.length === 1 &&
otherTypeNumbers.length === 1 &&
typeNumbers[0] === otherTypeNumbers[0]
);
}
function isTriangle(num) {
return ((8 * num + 1) ** 0.5 - 1) % 2 === 0;
}
function isSquare(num) {
return num ** 0.5 === parseInt(num ** 0.5, 10);
}
function isPentagonal(num) {
return ((24 * num + 1) ** 0.5 + 1) % 6 === 0;
}
function isHexagonal(num) {
return ((8 * num + 1) ** 0.5 + 1) % 4 === 0;
}
function isHeptagonal(num) {
return ((40 * num + 9) ** 0.5 + 3) % 10 === 0;
}
function isOctagonal(num) {
return ((3 * num + 1) ** 0.5 + 1) % 3 === 0;
}
const numberTypes = [
['triangle', isTriangle, []],
['square', isSquare, []],
['pentagonal', isPentagonal, []],
['hexagonal', isHexagonal, []],
['heptagonal', isHeptagonal, []],
['octagonal', isOctagonal, []]
];
const numsExcludingLastNeededType = new Set();
fillNumberTypes(n, numberTypes, numsExcludingLastNeededType);
const nNumberChains = [];
const [, , lastType] = numberTypes[n - 1];
for (let i = 0; i < lastType.length; i++) {
const startOfChain = lastType[i];
nNumberChains.push(
...getChains([startOfChain], n, numberTypes, numsExcludingLastNeededType)
);
}
const cyclicalChains = nNumberChains.filter(chain =>
isCyclicalChain(chain, n, numberTypes)
);
let sum = 0;
for (let i = 0; i < cyclicalChains.length; i++) {
for (let j = 0; j < cyclicalChains[0].length; j++) {
sum += cyclicalChains[i][j];
}
}
return sum;
}
```