最大可能的字母矩形

时间:2011-12-14 21:50:35

标签: algorithm optimization np-hard

  

编写程序以找到最大可能的字母矩形,这样每行形成一个单词(从左到右),每列形成一个单词(从上到下)。

我发现了这个有趣的问题。这不是家庭作业,尽管听起来可能如此。 (我不在学校)。我这样做是为了好玩。

  

示例

     

来自 cat car ape api rep ,< em> tip 我们得到以下矩形(这是一个正方形):

c a r
a p e
t i p

我最初的想法是构建某种前缀树,以便我可以检索以特定字符串开头的所有单词。当我们已经有2个或更多单词(从上到下或从左到右阅读)时,这将非常有用,我们需要找到要添加的下一个单词。

还有其他想法吗?

修改

这可以用长方体(3D矩形)来完成吗?

如果它需要在对角线上有有效的单词(想法信用:user645466);如何优化算法?

3 个答案:

答案 0 :(得分:12)

让D成为字典。修复m和n。我们可以将m×n矩形的问题表达为constraint satisfaction problem(CSP)。

  

x i,1 ... x i,n ∈D∀i∈{1,...,m}
  x 1,j ... x m,j ∈D∀j∈{1,...,n}
  x i,j ∈{A,...,Z}∀i∈{1,...,m},∀j∈{1,...,n}

解决CSP的一种非常常见的方法是将回溯与约束传播相结合。松散地说,回溯意味着我们选择一个变量,猜测它的值,并用一个较少的变量递归地求解子问题,约束传播意味着试图减少每个变量的可能性数量(可能为零,这意味着没有解决方案)。

例如,我们可以通过选择x 1,1 = Q来启动3×3网格。

Q??
???
???

使用英语词典时,x 1,2 和x 2,1 的唯一可能性是U(在Scrabble“words”之前)。

解决CSP的技巧是在回溯和约束传播之间取得平衡。如果我们根本不传播约束,那么我们只是使用蛮力。如果我们完美地传播约束,那么我们不需要回溯,但是运行本身解决NP难问题的传播算法可能相当昂贵。

在这个问题中,除非我们有良好的数据结构支持,否则在每个回溯节点处使用大字典将会变得昂贵。我将概述一种快速使用trieDAWG来计算字母集的方法,通过该字母集,前缀可以扩展为完整的单词。

在每个回溯节点,我们分配的变量集是一个Young画面。换句话说,在分配了它上面和左边的变量之前,不会分配任何变量。在下图中,.表示已分配的变量,*?表示未分配的变量。

.....*
...*??
...*??
..*???
*?????

标记为*的变量是下一个被赋值的候选变量。多次选择而不是每次选择固定变量的优点是某些变量排序可能比其他变量好得多。

对于每个*,对trie / DAWG进行两次查找,一次用于水平,一次用于垂直,并计算下一个可以出现的字母组的交集。一个经典策略是选择具有最少可能性的变量,以期更快地达到矛盾。我喜欢这种策略,因为当有一个零可能性的变量时它自然地修剪,当有一个变量时它自然地传播。通过缓存结果,我们可以非常快速地评估每个节点。

答案 1 :(得分:1)

给定给定长度的单词字典,创建两个新词典:第一个包含单词的所有单个字母前缀(所有字母可以是给定长度的单词的第一个字母),第二个包含所有字母单词的双字母前缀(两个字母的所有序列,可以是给定长度的单词的前两个字母)。你也可以做三重前缀,但你可能不需要超越它。

  1. 从词典中选择一个单词,将其命名为X。这将是矩阵的第一行。

  2. 使用您提供的方便列表检查X[1], X[2], ..., X[N]是否都是有效的单字母前缀。如果是,继续第3步;否则回到第1步。

  3. 从词典中选择一个单词,将其命名为Y。这将是矩阵的第二行。

  4. 使用您提供的方便列表,检查X[1] Y[1]X[2] Y[2],...,X[N] Y[N]是否都是有效的双字母前缀。如果是,继续第5步;否则回到第3步。如果这是字典中的最后一个字,那么一直回到第1步。

    ...

    2(N-1)。从词典中选择一个单词,将其命名为Z。这将是矩阵的第N行。

    2N。检查X[1] Y[1] ... Z[1]X[2] Y[2] ... Z[2],...,X[N] Y[N] ... Z[N]是字典中的所有字词。如果他们是,恭喜,你已经做到了!否则返回步骤2(N-1)。如果这是字典中的最后一个字,那么一直回到第2步(n-3)。

  5. 逻辑是一次一行地构建单词矩形,为行选择单词,然后检查列 完成单词。这比一次添加一个字母要快得多。

答案 2 :(得分:1)

  

为相同长度的词创建一个Bag [] = index然后创建   一个Tries数组,每个长度的wordList一个Trie

   Rectangle makeRectangle(length, height, rectangle)
    {
        if ( length == rectangle.length()) check if complete and return;
        checkIfPartialComplete - check columns for valid prefixes
        for ( i from 1 to grouplist[i-1])
        {
            newRectangle = append word[i] to rectangle 
            return makeRectangle(l,h, rectangle with appended word) if not equal to null
        }
    }


boolean checkPartial(int l, Trie trie)
{
    for ( int i =0 ; i < l; i++)
    {
        String col = getColumn(i);
        if (!trie.contains(col))
        {
            return false;
        }
    }
    return true;
}
boolean checkComplete(int l, Bag<String> lengthGroup)
{
    for ( int i=0; i < l ; i++)
    {
        String col = getColumn(i);
        if (!lengthGroup.contains(col))
        {
            return false;
        }
    }
    return true;
}