4

Pythonでnqueenの問題を解決しました。この解は、nXn のチェス盤に n 個のクイーンを配置する解の総数を出力しますが、n=15 で試してみると、答えを得るのに 1 時間以上かかります。誰でもコードを見て、このプログラムを高速化するためのヒントを教えてもらえますか...初心者のpythonプログラマー。

#!/usr/bin/env python2.7

##############################################################################
# a script to solve the n queen problem in which n queens are to be placed on
# an nxn chess board in a way that none of the n queens is in check by any other
#queen using backtracking'''
##############################################################################
import sys
import time
import array

solution_count = 0

def queen(current_row, num_row, solution_list):
    if current_row == num_row:
        global solution_count 
        solution_count = solution_count + 1
    else:
        current_row += 1
        next_moves = gen_nextpos(current_row, solution_list, num_row + 1)
        if next_moves:
            for move in next_moves:
                '''make a move on first legal move of next moves'''
                solution_list[current_row] = move
                queen(current_row, num_row, solution_list)
                '''undo move made'''
                solution_list[current_row] = 0
        else:
            return None

def gen_nextpos(a_row, solution_list, arr_size):
    '''function that takes a chess row number, a list of partially completed 
    placements and the number of rows of the chessboard. It returns a list of
    columns in the row which are not under attack from any previously placed
    queen.
    '''
    cand_moves = []
    '''check for each column of a_row which is not in check from a previously
    placed queen'''
    for column in range(1, arr_size):
        under_attack =  False
        for row in range(1, a_row):
            '''
            solution_list holds the column index for each row of which a 
            queen has been placed  and using the fact that the slope of 
            diagonals to which a previously placed queen can get to is 1 and
            that the vertical positions to which a queen can get to have same 
            column index, a position is checked for any threating queen
            '''
            if (abs(a_row - row) == abs(column - solution_list[row]) 
                    or solution_list[row] == column):
                under_attack = True
                break
        if not under_attack:
            cand_moves.append(column)
    return cand_moves

def main():
    '''
    main is the application which sets up the program for running. It takes an 
    integer input,N, from the user representing the size of the chessboard and 
    passes as input,0, N representing the chess board size and a solution list to
    hold solutions as they are created.It outputs the number of ways N queens
    can be placed on a board of size NxN.
    '''
    #board_size =  [int(x) for x in sys.stdin.readline().split()]
    board_size = [15]
    board_size = board_size[0]
    solution_list = array.array('i', [0]* (board_size + 1))
    #solution_list =  [0]* (board_size + 1)
    queen(0, board_size, solution_list)
    print(solution_count)


if __name__ == '__main__':
    start_time = time.time()
    main()
    print(time.time() 
4

6 に答える 6

5

N-Queens 問題へのバックトラッキング アルゴリズムは、最悪の場合は階乗アルゴリズムです。したがって、N=8 の場合は 8! 最悪の場合の解の数がチェックされ、N=9 の場合は 9! などです。ご覧のとおり、可能な解の数は非常に多く、非常に急速に増加します。信じられない場合は、電卓に行って、1 から始まる連続した数を掛け始めてください。電卓がメモリ不足になる速さを教えてください。

幸いなことに、考えられるすべてのソリューションをチェックする必要はありません。残念ながら、正しい解の数は依然としてほぼ階乗的な増加パターンに従います。したがって、アルゴリズムの実行時間は階乗のペースで増加します。

すべての正しい解を見つける必要があるため、プログラムを高速化するためにできることはあまりありません。検索ツリーから不可能な枝を刈り取る作業はすでにうまくいきました。他に大きな影響を与えるものはないと思います。それは単純に遅いアルゴリズムです。

于 2011-01-27T16:06:32.260 に答える
2

この質問を見ただけです。2つのソリューションに貢献したいと思います。

  1. これはすべての個別のソリューションを返します

  2. これは、見つかった最初の有効なソリューションを返します

フィードバックをお待ちしております。乾杯

于 2016-08-03T19:05:30.037 に答える
2

test_generators.pyN-Queens 問題の別の実装については、Python のソースを参照することをお勧めします。

Python 2.6.5 (release26-maint, Sep 12 2010, 21:32:47) 
[GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from test import test_generators as tg
>>> n= tg.Queens(15)
>>> s= n.solve()
>>> next(s)
[0, 2, 4, 1, 9, 11, 13, 3, 12, 8, 5, 14, 6, 10, 7]
>>> next(s)
[0, 2, 4, 6, 8, 13, 11, 1, 14, 7, 5, 3, 9, 12, 10]
于 2011-02-21T13:31:48.197 に答える
2

解の数は、Donald Knuth のランダム推定法を使用して推定できます。

クイーンが配置されていない状態から始めて、次の行に許可されるポジションの数は n です。位置の 1 つをランダムに選択し、次の行の許容される位置の数 (p) を計算し、これを n で乗算して、ソリューションの総数 (合計 = n * p) として保存し、許容される位置の 1 つをランダムに選択します。 .

この行について、次の行の許可された位置の数 (p) を計算し、解の総数をこれで倍増させます (合計 *= p)。ボードが解決できなくなるまで (解決の数がゼロになる)、またはボードが解決されるまで、これを繰り返します。

これを何度も繰り返して、解の平均数 (ゼロを含む) を計算します。これにより、解の数の迅速かつかなり正確な概算が得られ、その概算は、より多くの実行を行うほど改善されます。

これが理にかなっていることを願っています;)

于 2011-01-27T16:33:29.377 に答える
0

以下は私の PYTHON 実装です。より高速にするには、PYPY を使用することをお勧めします。

その速度は、O(1) 時間メソッドを使用して、次のクイーンが既にボードに配置されているものによって攻撃されているかどうかを確認することによって促進されます。

プログラムが「nqueen.py」であると仮定すると、それを実行する例は「python nqueen.py 6」です。ここで、6 は 6x6 ボードのサイズです。

#!/bin/python
#
# TH @stackoverflow, 2016-01-20, "N Queens" with an O(1) time method to check whether the next queen is attacked
#
import sys


board_size = int(sys.argv[1])
Attacked_H  = { i:0 for i in range(0, board_size) }
Attacked_DU = { i:0 for i in range(0, board_size*2) }
Attacked_DD = { i:0 for i in range(-board_size, board_size) }


def nqueen(B, N, row, col):
    if(row >= N):
        return 1
    if(col >= N):
        print "board:\n" + str.join("\n", ["_|"*q + "Q|" + "_|"*(board_size - q - 1) for q in B])
        return 0
    B[col] = row
    if(0==(Attacked_H[row] + Attacked_DU[row+col] + Attacked_DD[row-col])):
        [Attacked_H[row], Attacked_DU[row+col], Attacked_DD[row-col]] = [ 1,1,1 ]
        nqueen(B, N, 0, col + 1)
        [Attacked_H[row], Attacked_DU[row+col], Attacked_DD[row-col]] = [ 0,0,0 ]
    nqueen(B, N, row + 1, col)


nqueen(list(range(0, board_size)), board_size, 0, 0)
于 2016-01-20T23:17:07.300 に答える