Python, 1281.375 1268.625 바이트
우리는 각 결정이 다음 세 가지 형식 중 하나 인 라틴 정사각형을 한 번에 하나의 "결정"으로 인코딩합니다.
- 행 i , 열 j 에있는 숫자 ;
- 행 i에서 , 숫자 k 가 들어가는 열 ;
- 칼럼에서 J 숫자 열, K가 들어간다.
각 단계에서 이전 결정을 기반으로 할 수있는 모든 논리적 추론을 한 다음 가능한 적은 수의 선택을 통해 결정을 선택하므로 표시 할 비트 수가 가장 적습니다.
선택은 간단한 산술 디코더 (선택 수에 따라 div / mod)에 의해 제공됩니다. 그러나 잎 인코딩 일부 중복 : 만약 K의 선택의 모든 제품 번호이었던 사각으로 디코딩 m은 다음 케이 + m을 , K + 2⋅ m , K + 3⋅ m , ... 디코드 동일한 정방형 끝에 남은 상태가 있습니다.
이 중복성을 활용하여 정사각형의 크기를 명시 적으로 인코딩하지 않도록합니다. 압축 해제 기는 크기 1의 제곱을 해독하려고 시도합니다. 디코더가 남은 상태로 끝날 때마다 결과를 버리고 원래 숫자에서 m 을 빼고 크기를 1 씩 증가시킨 후 다시 시도합니다.
import numpy as np
class Latin(object):
def __init__(self, size):
self.size = size
self.possible = np.full((size, size, size), True, dtype=bool)
self.count = np.full((3, size, size), size, dtype=int)
self.chosen = np.full((3, size, size), -1, dtype=int)
def decision(self):
axis, u, v = np.unravel_index(np.where(self.chosen == -1, self.count, self.size).argmin(), self.count.shape)
if self.chosen[axis, u, v] == -1:
ws, = np.rollaxis(self.possible, axis)[:, u, v].nonzero()
return axis, u, v, list(ws)
else:
return None, None, None, None
def choose(self, axis, u, v, w):
t = [u, v]
t[axis:axis] = [w]
i, j, k = t
assert self.possible[i, j, k]
assert self.chosen[0, j, k] == self.chosen[1, i, k] == self.chosen[2, i, j] == -1
self.count[1, :, k] -= self.possible[:, j, k]
self.count[2, :, j] -= self.possible[:, j, k]
self.count[0, :, k] -= self.possible[i, :, k]
self.count[2, i, :] -= self.possible[i, :, k]
self.count[0, j, :] -= self.possible[i, j, :]
self.count[1, i, :] -= self.possible[i, j, :]
self.count[0, j, k] = self.count[1, i, k] = self.count[2, i, j] = 1
self.possible[i, j, :] = self.possible[i, :, k] = self.possible[:, j, k] = False
self.possible[i, j, k] = True
self.chosen[0, j, k] = i
self.chosen[1, i, k] = j
self.chosen[2, i, j] = k
def encode_sized(size, square):
square = np.array(square, dtype=int)
latin = Latin(size)
chosen = np.array([np.argmax(square[:, :, np.newaxis] == np.arange(size)[np.newaxis, np.newaxis, :], axis=axis) for axis in range(3)])
num, denom = 0, 1
while True:
axis, u, v, ws = latin.decision()
if axis is None:
break
w = chosen[axis, u, v]
num += ws.index(w)*denom
denom *= len(ws)
latin.choose(axis, u, v, w)
return num
def decode_sized(size, num):
latin = Latin(size)
denom = 1
while True:
axis, u, v, ws = latin.decision()
if axis is None:
break
if not ws:
return None, 0
latin.choose(axis, u, v, ws[num % len(ws)])
num //= len(ws)
denom *= len(ws)
return latin.chosen[2].tolist(), denom
def compress(square):
size = len(square)
assert size > 0
num = encode_sized(size, square)
while size > 1:
size -= 1
square, denom = decode_sized(size, num)
num += denom
return '{:b}'.format(num + 1)[1:]
def decompress(bits):
num = int('1' + bits, 2) - 1
size = 1
while True:
square, denom = decode_sized(size, num)
num -= denom
if num < 0:
return square
size += 1
total = 0
with open('latin_squares.txt') as f:
while True:
square = [list(map(int, l.split(','))) for l in iter(lambda: next(f), '\n')]
if not square:
break
bits = compress(square)
assert set(bits) <= {'0', '1'}
assert square == decompress(bits)
print('Square {}: {} bits'.format(len(square), len(bits)))
total += len(bits)
print('Total: {} bits = {} bytes'.format(total, total/8.0))
산출:
Square 1: 0 bits
Square 2: 1 bits
Square 3: 3 bits
Square 4: 8 bits
Square 5: 12 bits
Square 6: 29 bits
Square 7: 43 bits
Square 8: 66 bits
Square 9: 94 bits
Square 10: 122 bits
Square 11: 153 bits
Square 12: 198 bits
Square 13: 250 bits
Square 14: 305 bits
Square 15: 363 bits
Square 16: 436 bits
Square 17: 506 bits
Square 18: 584 bits
Square 19: 674 bits
Square 20: 763 bits
Square 21: 877 bits
Square 22: 978 bits
Square 23: 1097 bits
Square 24: 1230 bits
Square 25: 1357 bits
Total: 10149 bits = 1268.625 bytes
0
하지만n-1
:)