6

逆ボーグル問題を解こうとしています。簡単に言えば、単語のリストが与えられた場合、リスト内の単語と同じ数の単語が隣接する文字のシーケンスで見つかる 4x4 の文字グリッドを作成します (文字は直交方向と斜め方向の両方で隣接しています)。

既知のボードを使用して解決したくありません。これは簡単な TRIE 問題であり、人々の CS プロジェクトのためにここで議論/解決されています。

単語リストの例:

margays, jaguars, cougars, tomcats, margay, jaguar, cougar, pumas, puma, toms

解決:

ATJY
CTSA
OMGS
PUAR

この問題は(私にとって)難しいです。私がこれまでに持っているアルゴリズム:

  1. 入力の各単語について、それ自体が合法的にボードに表示される可能性のあるすべての方法のリストを作成します。
  2. これらのボードに単語 #2 を配置するすべての可能な組み合わせを試し、競合のないものを保持します。
  3. リストの最後まで繰り返します。
  4. ...
  5. 利益!!!(/を読んでいる人向け)

明らかに、実装の詳細があります。最初に最も長い単語から始めます。他の単語の部分文字列である単語を無視します。

約 0.4 秒で、7 文字の単語に対して 68,000 の可能なすべてのボードを生成できます。その後、さらに 7 文字のボードを追加すると、68k x 68k のボード x 7 の比較が必要になります。解決時間が氷河になります。

これを行うためのより良い方法があるはずです!!!!

いくつかのコード:

BOARD_SIDE_LENGTH = 4

class Board:
    def __init__(self):
        pass

    def setup(self, word, start_position):
        self.word = word
        self.indexSequence = [start_position,]
        self.letters_left_over = word[1:]
        self.overlay = []
        # set up template for overlay.  When we compare boards, we will add to this if the board fits
        for i in range(BOARD_SIDE_LENGTH*BOARD_SIDE_LENGTH):
            self.overlay.append('')
        self.overlay[start_position] = word[0]
        self.overlay_count = 0

    @classmethod
    def copy(boardClass, board):
        newBoard = boardClass()
        newBoard.word = board.word
        newBoard.indexSequence = board.indexSequence[:]
        newBoard.letters_left_over = board.letters_left_over
        newBoard.overlay = board.overlay[:]
        newBoard.overlay_count = board.overlay_count
        return newBoard

    # need to check if otherboard will fit into existing board (allowed to use blank spaces!)
    # otherBoard will always be just a single word
    @classmethod
    def testOverlay(self, this_board, otherBoard):
        for pos in otherBoard.indexSequence:
            this_board_letter = this_board.overlay[pos]
            other_board_letter = otherBoard.overlay[pos]
            if this_board_letter == '' or other_board_letter == '':
                continue
            elif this_board_letter == other_board_letter:
                continue
            else:
                return False
        return True

    @classmethod
    def doOverlay(self, this_board, otherBoard):
        # otherBoard will always be just a single word
        for pos in otherBoard.indexSequence:
            this_board.overlay[pos] = otherBoard.overlay[pos]
        this_board.overlay_count = this_board.overlay_count + 1

    @classmethod
    def newFromBoard(boardClass, board, next_position):
        newBoard = boardClass()
        newBoard.indexSequence = board.indexSequence + [next_position]
        newBoard.word = board.word
        newBoard.overlay = board.overlay[:]
        newBoard.overlay[next_position] = board.letters_left_over[0]    
        newBoard.letters_left_over = board.letters_left_over[1:]
        newBoard.overlay_count = board.overlay_count
        return newBoard

    def getValidCoordinates(self, board, position):
        row = position / 4
        column = position % 4
        for r in range(row - 1, row + 2):
            for c in range(column - 1, column + 2):
                if r >= 0 and r < BOARD_SIDE_LENGTH and c >= 0 and c < BOARD_SIDE_LENGTH:
                    if (r*BOARD_SIDE_LENGTH+c not in board.indexSequence):
                        yield r, c

class boardgen:
    def __init__(self):
        self.boards = []

    def createAll(self, board):
        # get the next letter
        if len(board.letters_left_over) == 0:
            self.boards.append(board)
            return
        next_letter = board.letters_left_over[0]    
        last_position = board.indexSequence[-1]
        for row, column in board.getValidCoordinates(board, last_position):
            new_board = Board.newFromBoard(board, row*BOARD_SIDE_LENGTH+column)
            self.createAll(new_board)

そして、次のように使用します。

words = ['margays', 'jaguars', 'cougars', 'tomcats', 'margay', 'jaguar', 'cougar', 'pumas', 'puma']
words.sort(key=len)

first_word = words.pop()

# generate all boards for the first word
overlaid_boards = []
for i in range(BOARD_SIDE_LENGTH*BOARD_SIDE_LENGTH):
    test_board = Board()
    test_board.setup(first_word, i)
    generator = boardgen()
    generator.createAll(test_board)
    overlaid_boards += generator.boards
4

2 に答える 2

2

これは興味深い問題です。最適化された完全な解決策を思いつくことはできませんが、試してみてほしいアイデアがいくつかあります。

難しいのは、すべての単語を収めることができない場合に最適なサブセットを見つける必要があることです。これにより、複雑さが大幅に増します。明らかに機能しない単語の組み合わせを排除することから始めます。16 文字を超える単語はすべてカットします。必要な一意の文字の数を数えます。同じ単語で繰り返される文字を考慮してください。たとえば、リストに「eagle」が含まれている場合、単語の両端に同じ「e」を使用することは許可されていないと思います。必要な文字のリストが 16 を超える場合は、いくつかの単語を削除する必要があります。どの単語を最初にカットするかを考え出すのは、興味深いサブ問題です... 私は、最も使用頻度の低い文字を含む単語から始めます。すべてのサブリストをスコアでソートすると役立つ場合があります。

次に、語長の合計が 16 未満の簡単なケースを実行できます。その後、単語の完全なリストから始めて、その解決策があるかどうかを確認します。そうでない場合は、ドロップする単語を見つけて、もう一度やり直してください。

単語リストが与えられた場合、コア アルゴリズムは、それらの単語をすべて含むグリッド (存在する場合) を見つけることです。

愚かな力ずくの方法は、必要な文字で可能なすべてのグリッドを反復処理し、それぞれをテストして、すべての単語が適合するかどうかを確認することです。かなり厳しいですが、ミドルケースは 16 です! = 2x10exp13 ボード。n 個の一意の文字の正確な式は... (16!)/(16-n)! x pow(n, 16-n)。これは、3x10exp16 の範囲で最悪のケースを示します。あまり扱いにくい。回転や反転を回避できたとしても、検索スペースの 1/16 しか節約できません。

やや賢い貪欲なアルゴリズムは、難易度や長さなどの基準で単語を並べ替えることです。再帰的な解決策は、リストに残っている一番上の単語を取得し、それをグリッドに配置しようとすることです。次に、そのグリッドと残りの単語リストで再帰します。単語がなくなる前にグリッドを埋めてしまった場合は、後戻りして単語を配置する別の方法を試す必要があります。貪欲なアプローチは、最初に最も多くの文字を再利用する配置を試すことです. 多少の剪定はできます。グリッドに残っているスペースの数が、必要な一意の文字の残りのセットよりも少ない場合はいつでも、それらのサブツリーを削除できます。特に残りのグリッド スペースが最後の単語の長さよりも小さい場合は、切り取ることができる解決策がないことが明らかなケースが他にもいくつかあります。この検索スペースは、単語の長さと再使用される文字数によって異なります。総当たりよりはましだと確信していますが、問題を合理的にするのに十分かどうかはわかりません。

スマートな方法は、何らかの形式の動的計画法を使用することです。このための完全なアルゴリズムはよくわかりません。1 つのアイデアは、文字のツリーまたはグラフを作成し、各文字を単語リスト内の「隣接する」文字に接続することです。次に、最も関連性の高い文字から始めて、ツリーをグリッドにマッピングしようとします。単語リストのほとんどを完成させる文字を常に配置します。グリッド内に同じ文字が複数ある場合を処理する何らかの方法が必要です。また、注文方法がわからないので、すべての組み合わせを検索する必要はありません。

最良の方法は、すべてのサブワード リストも含む動的なアルゴリズムを使用することです。したがって、リストに「fog」と「fox」があり、fox は適合せず、fog は適合する場合、リストの両方のバージョンですべてを実行する必要なく、それを処理できます。各ソリューションをスコアでランク付けする必要があるため、複雑さが増しています。しかし、すべての単語が収まらない場合は、多くの時間を節約できます。

これで頑張ってください。

于 2014-02-07T13:37:02.220 に答える