| Bytes | Lang | Time | Link |
|---|---|---|---|
| 322 | Python | 241202T131320Z | 138 Aspe |
| nan | 200516T141351Z | l4m2 | |
| 4442 | Rust | 200517T015304Z | Anders K |
| 322 | JavaScript Node.js | 200513T023418Z | Arnauld |
Python, \$n\leq 32\$ in 2 seconds
Port of @Anders Kaseorg's Rust answer in Python.
from collections import defaultdict
def main():
for n in range(63):
if 0xa05 & (1 << (n % 12)) == 0:
print(f"{n} 0")
else:
count = [(((1 << n) - 1) << 1, 1)]
MASK = (1 << (n + 1)) - 1
for k in range(n, 0, -1):
for i in range(k - 1):
count1_dict = defaultdict(int)
for b, c in count:
not_b = (~b) & MASK
if (not_b & (3 << i)) == 0:
b1 = b & ~(3 << i)
count1_dict[b1] += c
if (not_b & (6 << i)) == 0:
b1 = b & ~(6 << i)
count1_dict[b1] += c
if (b & (2 << i)) == 0:
b1 = b | (2 << i)
count1_dict[b1] += c
count = list(count1_dict.items())
if i == 1:
count = [(b, c) for b, c in count if (b & 6) != 2]
count = [(b, c) for b, c in count if not (b & (1 << k))]
assert len(count) == 1
assert count[0][0] == 0
print(f"{n} {count[0][1]}")
if __name__ == "__main__":
main()
\$T(33) = 3688972842502560 \$
> 1 0
> 2 1
> 3 0
> 4 0
> 5 0
> 6 0
> 7 0
> 8 0
> 9 2
> 10 0
> 11 8
> 12 12
> 13 0
> 14 72
> 15 0
> 16 0
> 17 0
> 18 0
> 19 0
> 20 0
> 21 185328
> 22 0
> 23 4736520
> 24 21617456
> 25 0
> 26 912370744
> 27 0
> 28 0
> 29 0
> 30 0
> 31 0
> 32 0
> 33 3688972842502560
Process returned 0 (0x0) execution time : 71.730 s
Press any key to continue.
Code
#include <map>
#include <stdio.h>
#include <algorithm>
const int N = 33;
typedef unsigned long long ulong;
#define long ulong
std::map<ulong, long> A, B;
int i; long base;
template<bool last = false>
void bitfsh(ulong j, ulong d) {
if (!j) {
if(!last || d==0) B[d] += base;
return;
}
int p = sizeof(ulong)*8-1-__builtin_clzll(j);
if (d & 2ULL<<p) {
bitfsh<last> (j ^ 1ULL<<p, d ^ 3ULL<<p);
}
if (p && (j & 1ULL<<p-1)) {
bitfsh<last> (j ^ 3ULL<<p-1, d ^ 1ULL<<p);
}
}
template<bool last = false>
long run() {
B.clear();
for (auto p=A.begin(); p!=A.end(); ++p) {
ulong j = (*p).first;
if (j%65536==0) fprintf(stderr, "%d %lld\r", i, j);
base = (*p).second;
if(base) bitfsh<last> (j, (1ULL<<i)-1);
}
std::swap (A, B);
fprintf(stderr, "%60c\r", ' ');
return A[0];
}
const ulong fs = sizeof(long) << N-1;
int main() {
A[0] = 1;
for (i=1; i<N; ++i) {
//fprintf(stderr, "%d\n", i);
printf ("> %d %llu\n", i, run ());
}
printf ("> %d %llu\n", i, run<true> ());
exit(0);
}
T(45) = 1.9935928828199593078904655e+31
Ran in 31953.963 s on my computer(including state backups), and use approximately 4.5GB disk.
Use @Anders Kaseorg 's solution but with disk as storage. For each \$k,i\$ amounts of items can be found here. TIO
Rust, \$n \le 44\$ in 42 seconds
Build with rustc -O. Uses about 800 MiB of memory for \$n = 38\$, and \$39 \le n \le 44\$ are trivial. \$n = 45\$ will almost definitely run out of both time and memory on any reasonable system.
It works by dynamic programming where the states are the presence or absence of hexagons at \$(k - 1, 1), \dotsc, (k - 1, i), (k, i + 1), \dotsc, (k, k)\$; we advance \$i\$ to \$i + 1\$ by considering the addition of tribone \$(k, i + 1), (k - 1, i), (k - 1, i + 1)\$ or \$(k, i + 1), (k - 1, i + 1), (k, i + 2)\$.
use std::iter::Peekable;
use std::mem;
struct Merge<Xs: Iterator, Ys: Iterator>(Peekable<Xs>, Peekable<Ys>);
impl<Xs: Iterator<Item = (u64, u128)>, Ys: Iterator<Item = (u64, u128)>> Iterator
for Merge<Xs, Ys>
{
type Item = (u64, u128);
fn next(&mut self) -> Option<(u64, u128)> {
if let Some(x) = self.0.peek() {
if let Some(y) = self.1.peek() {
if x.0 < y.0 {
self.0.next()
} else if x.0 > y.0 {
self.1.next()
} else {
let x = self.0.next().unwrap();
let y = self.1.next().unwrap();
Some((x.0, x.1 + y.1))
}
} else {
self.0.next()
}
} else {
self.1.next()
}
}
}
fn main() {
for n in 0..63 {
if 0xa05 & 1 << n % 12 == 0 {
println!("{} 0", n);
} else {
let mut count: Vec<(u64, u128)> = vec![(!(!0 << n) << 1, 1)];
let mut count1 = vec![];
for k in (1..n + 1).rev() {
for i in 0..k - 1 {
count1.extend(Merge(
Merge(
count
.iter()
.filter(|&&(b, _)| !b & 3 << i == 0)
.map(|&(b, c)| (b & !(3 << i), c))
.peekable(),
count
.iter()
.filter(|&&(b, _)| !b & 6 << i == 0)
.map(|&(b, c)| (b & !(6 << i), c))
.peekable(),
)
.peekable(),
count
.iter()
.filter(|&&(b, _)| b & 2 << i == 0)
.map(|&(b, c)| (b | 2 << i, c))
.peekable(),
));
mem::swap(&mut count, &mut count1);
count1.clear();
if i == 1 {
count.retain(|&(b, _)| b & 6 != 2);
}
}
count.retain(|&(b, _)| b & 1 << k == 0);
}
assert_eq!(count.len(), 1);
assert_eq!(count[0].0, 0);
println!("{} {}", n, count[0].1);
}
}
}
(TIO times out after \$n = 37\$.)
Output
0 1
1 0
2 1
3 0
4 0
5 0
6 0
7 0
8 0
9 2
10 0
11 8
12 12
13 0
14 72
15 0
16 0
17 0
18 0
19 0
20 0
21 185328
22 0
23 4736520
24 21617456
25 0
26 912370744
27 0
28 0
29 0
30 0
31 0
32 0
33 3688972842502560
34 0
35 717591590174000896
36 9771553571471569856
37 0
38 3177501183165726091520
39 0
40 0
41 0
42 0
43 0
44 0
JavaScript (Node.js), N = 22 25 32 in ~2 seconds
A recursive search using bit masks and a cache to keep track of patterns whose result is already known.
It doesn't make much sense to try go further in Node. Using a binary matrix is significantly slower and BigInts are even slower. It should rather be ported to a language natively supporting 64-bit integers.
'use strict';
let ts = new Date;
for(let n = 0; n <= 32; n++) {
console.log(
n.toString().padStart(2) + ' ' +
solve(n).toString().padStart(10) + ' ' +
'(' + ((new Date - ts) / 1000).toFixed(2) + ')'
);
}
function solve(n) {
// trivial cases
if(![0, 2, 9, 11].includes(n % 12)) {
return 0;
}
if(n == 0) {
return 1;
}
// We work on a triangle stored as an array of bit masks:
// 8 7 6 5 4 3 2 1 0 |
// -------------------+--- With this format, the tribones
// . . . . . . . . A | 0 are turned into the following
// . . . . . . . A A | 1 trominos:
// . . . . . . B B C | 2
// . . . . . D B C C | 3 X O and . X
// . . . . D D E E F | 4 O . O O
// . . . G H H E F F | 5
// . . G G H I I J J | 6 where 'X' is the arbitrary anchor
// . K L L M I N J O | 7 point used in this code
// K K L M M N N O O | 8
let a = Array(n).fill(0),
cache = a.map(_ => new Object);
// recursive search, starting at (x, y) = (0, 0)
return (function search(x, y) {
// if we've reached the last row, make sure it's complete
if(y == n - 1) {
if(a[y] == (1 << n) - 1) {
return 1;
}
return 0;
}
// if we are beyond the last column, go on with the next row
if(x < 0) {
y++;
// either return the result from the cache right away
if(cache[y][a[y]] !== undefined) {
return cache[y][a[y]];
}
// or do a full search
return cache[y][a[y]] = search(y, y);
}
// if (x, y) is already set, advance to the next column
if(a[y] >> x & 1) {
return search(x - 1, y);
}
let res = 0;
// try to insert X O
// O .
if(x && !(a[y] >> x - 1 & 1)) {
a[y] ^= 3 << x - 1;
a[y + 1] ^= 1 << x;
res += search(x - 2, y);
a[y] ^= 3 << x - 1;
a[y + 1] ^= 1 << x;
}
// try to insert . X
// O O
if(!(a[y + 1] >> x + 1 & 1)) {
a[y] ^= 1 << x;
a[y + 1] ^= 3 << x;
res += search(x - 1, y);
a[y] ^= 1 << x;
a[y + 1] ^= 3 << x;
}
return res;
})(0, 0);
}
Output
0 1 (0.00)
1 0 (0.00)
2 1 (0.00)
3 0 (0.00)
4 0 (0.00)
5 0 (0.00)
6 0 (0.00)
7 0 (0.00)
8 0 (0.00)
9 2 (0.00)
10 0 (0.00)
11 8 (0.00)
12 12 (0.01)
13 0 (0.01)
14 72 (0.01)
15 0 (0.01)
16 0 (0.01)
17 0 (0.01)
18 0 (0.01)
19 0 (0.01)
20 0 (0.01)
21 185328 (0.05)
22 0 (0.05)
23 4736520 (0.24)
24 21617456 (0.60)
25 0 (0.60)
26 912370744 (2.18)
27 0 (2.18)
28 0 (2.18)
29 0 (2.18)
30 0 (2.18)
31 0 (2.18)
32 0 (2.18)