絶望的な場合は、パズルをブルート フォースすることができます。私は通常、パズルに慣れるための最初のステップとしてこれを行います。NxN
基本的に、次の制約に従って、正方形に 1 から N までの整数を入力する必要があります。
- 各整数は、すべての行に 1 回だけ表示されます
- 各整数は、すべての列に 1 回だけ表示されます
- 行「手がかり」は満たされています
- 列「手がかり」は満たされています
ブルート フォース ソリューションは次のように機能します。まず、ボードを整数の 2D 配列として表します。次にis_valid_solution
、ボードが上記の制約を満たしている場合に True を返し、そうでない場合に False を返す関数を作成します。この部分は、 で比較的簡単に実行できますO(N^2)
。
最後に、可能なボードの順列を繰り返し、is_valid_solution
順列ごとに呼び出します。それが True を返したら、解決策が見つかりました。考えられる取り決めは全部あるN^(NxN)
ので、完全な解は になりますO(N^(NxN))
。検索スペースを減らすために上記の制約を使用することで、より良い結果を得ることができます。
上記の方法は、実行に比較的長い時間がかかりO(N^(NxN))
ます (アルゴリズムにとってはかなり恐ろしいことです) が、(最終的には) 解決策が得られます。それが機能するようになったら、より良い方法を考えてみてください。行き詰まったら、ここに戻ってきてください。
編集
上記の代わりに、空のボードから検索 (深さ優先など) を実行することをお勧めします。検索を繰り返すたびに、テーブルの 1 つのセルに数値を入力します (ただし、制約に違反することはありません)。たまたまボードがいっぱいになったら、完了です。
これは、再帰的な力ずくの深さ優先検索の擬似コードです。検索はNxN
ノードの深さまで行われ、各ノードでの分岐係数は最大でN
です。1 + N + N^2 + ... + N^(N-1)
これは、最大でまたは(N^N-1)/(N-1)
ノードを調べる必要があることを意味します。これらのノードのそれぞれについてis_valid_board
、最悪の場合 (ボードがいっぱいの場合) O(N^2) である which を呼び出す必要があります。
def fill_square(board, row, column):
if row == column == N-1: # the board is full, we're done
print board
return
next_row, next_col = calculate_next_position(row, col)
for value in range(1, N+1):
next_board = copy.deepcopy(board)
next_board[row][col] = value
if is_valid_board(next_board):
fill_square(next_board, next_row, next_col)
board = initialize_board()
fill_square(board, 0, 0)
この関数calculate_next_position
は、次に塗りつぶす正方形を選択します。これを行う最も簡単な方法は、ボードのスキャンライン トラバーサルです。よりスマートな方法は、行と列を交互に埋めることです。