この問題を解決するためのよく知られた方法があります。 x_1、...、x_nをn番目のボタンを解の一部として押したかどうかに応じた変数をa_1、...、a_nを初期状態とする。
のは、あなたは3x3の問題を解決しているとしましょう、と変数は次のように設定されています
x_1 x_2 x_3
x_4 x_5 x_6
x_7 x_8 x_9
と、この初期状態は次のとおりです。
a_1 a_2 a_3
a_4 a_5 a_6
a_7 a_8 a_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
これで、この連立方程式の集合をガウス消去法で解くことができます。 2を法とする算術演算をしているので、実数よりも連立方程式よりも実際には簡単です。たとえば、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]))
一度に1行ずつ初期状態にします。これは、すべてのライトをオフにするために押す必要のあるスイッチを返します。
これは私のラップトップで0.5秒未満で50x50の問題を解決します。
[Lights Out](http://en.wikipedia.org/wiki/Lights_Out_%28game%29)も参照してください。 – trashgod