fork download
  1. # your code goes hereimport sys
  2. import sys
  3. exec(sys.stdin.read())
Success #stdin #stdout 2.5s 17696KB
stdin
import sys
sys.setrecursionlimit(5000)

def get_variants(poly):
    variants = []
    current = list(poly)
    for _ in range(2):
        for _ in range(4):
            variants.append(tuple(sorted(current)))
            current = [(y, -x) for x, y in current]
        current = [(x, -y) for x, y in current]
    unique_variants = set()
    for v in variants:
        min_x = min(p[0] for p in v)
        min_y = min(p[1] for p in v)
        norm = tuple(sorted((x - min_x, y - min_y) for x, y in v))
        unique_variants.add(norm)
    return unique_variants

def canonical(poly):
    return min(get_variants(poly))

memo_gen = {}
def get_free_polyominoes(n):
    if n in memo_gen: return memo_gen[n]
    if n == 1:
        return {((0,0),)}
    prev = get_free_polyominoes(n-1)
    result = set()
    for p in prev:
        p_set = set(p)
        for x, y in p_set:
            for dx, dy in [(0,1), (0,-1), (1,0), (-1,0)]:
                nx, ny = x+dx, y+dy
                if (nx, ny) not in p_set:
                    new_p = p_set | {(nx, ny)}
                    result.add(canonical(new_p))
    memo_gen[n] = result
    return result

def has_hamiltonian(poly):
    n = len(poly)
    adj = {pt: [] for pt in poly}
    for x, y in poly:
        for dx, dy in [(0,1), (0,-1), (1,0), (-1,0)]:
            nb = (x+dx, y+dy)
            if nb in poly:
                adj[(x,y)].append(nb)
    for pt in poly:
        if not adj[pt] and n > 1: return False
    deg1 = [pt for pt in poly if len(adj[pt]) == 1]
    if len(deg1) > 2: return False
    start_nodes = deg1 if deg1 else list(poly)
    poly_list = list(poly)
    idx_map = {pt: i for i, pt in enumerate(poly_list)}
    def dfs(u_idx, visited_mask, count):
        if count == n: return True
        u = poly_list[u_idx]
        for v in adj[u]:
            v_idx = idx_map[v]
            if not (visited_mask & (1 << v_idx)):
                if dfs(v_idx, visited_mask | (1 << v_idx), count + 1):
                    return True
        return False
    for start in start_nodes:
        s_idx = idx_map[start]
        if dfs(s_idx, 1 << s_idx, 1):
            return True
    return False

print("START_CALC")
for n in [2, 4, 6, 8, 10]:
    polys = get_free_polyominoes(n)
    count = 0
    for p in polys:
        if has_hamiltonian(p):
            count += 1
    print(f"Size {n}: {count}")
print("END_CALC")
stdout
START_CALC
Size 2: 1
Size 4: 4
Size 6: 18
Size 8: 115
Size 10: 781
END_CALC