이 문제를 해결하기위한 잘 알려진 방법이 있습니다. x_1, ..., x_n을 n 번째 버튼을 솔루션의 일부로 누르는 지 여부에 해당하는 변수로 놓고 a_1, ..., a_n을 초기 상태로 놓습니다. 당신은 몇 가지를 기록 할 수
a_1 a_2 a_3
a_4 a_5 a_6
a_7 a_8 a_9
지금 :
의 당신이 3 × 3의 문제를 해결하고 있다고 가정 해 봅시다, 그리고 변수는 다음과 같이 설정됩니다 :
x_1 x_2 x_3
x_4 x_5 x_6
x_7 x_8 x_9
을이 초기 상태입니다 솔루션이 만족해야하는 방정식 (모듈로 2)이것은 기본적으로 스위치가 특정 조명을 토글하게하는 규칙을 인코딩합니다.
a_1 = x_1 + x_2 + x_4
a_2 = x_1 + x_2 + x_3 + x_5
...
a_5 = x_2 + x_4 + x_5 + x_6 + x_8
...
a_9 = x_6 + x_8 + x_9
이제 가우시안 제거를 사용하여이 연립 방정식을 풀 수 있습니다. 왜냐하면 당신은 modulo 2로 계산하기 때문에, 실제로는 실수에 대한 연립 방정식보다 약간 쉽습니다. 예를 들어, 두 번째 방정식에서 x_1을 제거하려면 방정식에 첫 번째 방정식을 추가하면됩니다.
a_1 + a_2 = (x_1 + x_2 + x_4) + (x_1 + x_2 + x_3 + x_5) = x_3 + x_4 + x_5
즉, 여기서 산술 모듈 (2)의 가우스 소거법 알고리즘이다 :
- 그것의 X_1와 방정식을 지정. 이름을 E_1로 지정하십시오.
- x_1이 포함 된 다른 모든 수식에 E_1을 추가하십시오.
- x_2, x_3, ...., x_n에 대해 반복하십시오.
이제 E_n은 x_n 만 포함하는 방정식입니다. x_n의 값을 이전 방정식으로 대체 할 수 있습니다. E_ {n-1}, ..., E_1에 대해 반복하십시오.
전체적으로 O (n^3) 연산의 문제를 해결합니다.
여기에 몇 가지 코드가 있습니다.
class Unsolvable(Exception):
pass
def switches(vs):
n, m = len(vs), len(vs[0])
eqs = []
for i in xrange(n):
for j in xrange(m):
eq = set()
for d in xrange(-1, 2):
if 0 <= i+d < n: eq.add((i+d)*m+j)
if d != 0 and 0 <= j+d < m: eq.add(i*m+j+d)
eqs.append([vs[i][j], eq])
N = len(eqs)
for i in xrange(N):
for j in xrange(i, N):
if i in eqs[j][1]:
eqs[i], eqs[j] = eqs[j], eqs[i]
break
else:
raise Unsolvable()
for j in xrange(i+1, N):
if i in eqs[j][1]:
eqs[j][0] ^= eqs[i][0]
eqs[j][1] ^= eqs[i][1]
for i in xrange(N-1, -1, -1):
for j in xrange(i):
if i in eqs[j][1]:
eqs[j][0] ^= eqs[i][0]
eqs[j][1] ^= eqs[i][1]
return [(i//m,i%m) for i, eq in enumerate(eqs) if eq[0]]
print switches(([1, 0, 0], [0, 1, 0], [0, 0, 1], [0, 0, 0]))
한 번에 한 행 씩 초기 상태로 지정하십시오. 모든 표시등을 끄기 위해 눌러야하는 스위치를 반환합니다.
내 랩톱에서 0.5 초 이내에 50x50 문제를 해결합니다.
[Lights Out] (http://en.wikipedia.org/wiki/Lights_Out_%28game%29)도 참조하십시오. – trashgod