Python 如何从字典中建立一个比暴力更好的单词板?

Python 如何从字典中建立一个比暴力更好的单词板?,python,algorithm,Python,Algorithm,考虑以下字母排列: B O A N R I D E N T 从上面的字母开始,从下面的两个字母中选择一个,Plinko样式,直到到达底部。无论你选择哪条路,你都会创造一个四个字母的单词:邦德、骨头、无聊、出生、裸露、谷仓、贝恩或诱饵。事实上,登特在底部的读数只是一个很好的巧合 我想帮助找出一个算法,可以设计这样一个布局,其中从上到下的每个可能路径从(提供的)字典生成一个不同的单词。程序的输入将是起始字母(本例中为B)和字长n(本例中为4)。它会返回组成这样一个布局的字母,或

考虑以下字母排列:

    B
   O A
  N R I
 D E N T
从上面的字母开始,从下面的两个字母中选择一个,Plinko样式,直到到达底部。无论你选择哪条路,你都会创造一个四个字母的单词:邦德、骨头、无聊、出生、裸露、谷仓、贝恩或诱饵。事实上,登特在底部的读数只是一个很好的巧合

我想帮助找出一个算法,可以设计这样一个布局,其中从上到下的每个可能路径从(提供的)字典生成一个不同的单词。程序的输入将是起始字母(本例中为B)和字长n(本例中为4)。它会返回组成这样一个布局的字母,或者一条消息说这是不可能的。它不必是确定性的,因此它可以用相同的输入生成不同的布局


到目前为止,我还没有想到比暴力手段更好的方法。也就是说,对于所有为布局底部选择字母的
26^[(n+2)(n-1)/2]
方法,检查所有可能的
2^(n-1)
路径是否都给出字典中的单词。我考虑过某种前缀树,但路径可以交叉并共享字母这一事实让我感到困惑。我对Python非常熟悉,但至少我希望有一种算法或方法可以解决这个问题。谢谢

假设底部的
V W X Y Z
实际上完成了单词

    B
   A O
  I R N
 T N E D
V W X Y Z
我们可以使用非常严格的启发式实现回溯搜索,似乎任何错误的路径都不会走得太远

在一个简单的树中插入所有以相同字母开头的
n
大小的单词,如下所示。现在执行深度优先搜索,断言以下内容:每个连续级别需要一个额外的“共享”字母,这意味着该级别上的
p(字母)
实例,另外还要求其两个子级是相同的字母(例如,级别2括号中的两个
R
s可以是“共享的”因为他们的孩子是一样的)

什么是
p(字母)
?当然是帕斯卡三角形
n choose r
是根据Plinko board,在这个简单树的相关级别上所需的字母实例数。在第三级,如果我们选择了
R
R
,我们需要3个
N
s和3个
E
s来表示该级别上的“共享”字母。3个
N
s中的每一个都必须有相同的子字母(在本例中为W,X),3个
E
s中的每一个也必须有(X,Y)

更新 出于好奇,这里有一些:)

来自itertools导入组合的

从复制导入deepcopy
#假设所有的话都开始了
#用同样的字母和
#长度相同
def插入(字、i、树):
如果i==len(单词):
返回
如果树中有单词[i]:
插入(word,i+1,树[word[i]])
其他:
树[word[i]={}
插入(word,i+1,树[word[i]])
#帕斯卡三角形
def get_next_需要(需要):
next_needed=[[1,无,0]+[None]*(len(needed)-1)+[[1,无,0]]
对于i,u在枚举中(需要):
如果i==len(需要)-1:
下一步需要[i+1]=[1,无,0]
其他:
下一个_needed[i+1]=[needed[i][0]+needed[i+1][0],无,0]
需要时返回下一个
def get_候选人(下一个需要、选中、家长):
全局日志
如果记录:
打印“获取候选项:父项:%s”%parents
#对于每个选择的节点,我们需要两个子节点。
#角点只有一个共享节点,而
#每组中的其他人都是相同的
#必须有一对完全相同的孩子
#给小组中的其他人。此外
#共享序列在每个组的末尾匹配。
#I(R)(R)N
#   / \      / \     / \     / \
#T(N)(N)E(N)E D
#迭代父对象,选择
#每个节点有两个节点
定义g(cs、s、序列、i、h):
如果记录:
打印“cs,seq,s,i,h:%s,%s,%s,%s,%s”%(cs,s,seq,i,h)
#基本情况下,我们得到了一个候选序列
如果i==len(父母):
返回[(cs,s,seq)]
#角落里的左边字符是
#武断的;下一个,共享。
#左上角:
如果i==0:
候选人=[]
对于组合中的(l,r)(选择[0]。键(),2):
_cs=深度复制(cs)
_cs[0]=[1,l,1]
_cs[1][1]=r
_cs[1][2]=1
_s=s[:]
_s、 扩展([选择的[0][l],选择的[0][r]])
_h=深度复制(h)
#将索引保存在
#为父节点选择的节点
_h[父母[1]]=[1,2]
扩展(g(_-cs,_-s,l+r,1,_-h))
_cs=深度复制(cs)
_cs[0]=[1,r,1]
_cs[1][1]=l
_cs[1][2]=1
_s=s[:]
_s、 扩展([选择的[0][r],选择的[0][l]])
_h=深度复制(h)
#将索引保存在
#为父节点选择的节点
_h[父母[1]]=[1,2]
扩展(g(_-cs,_-s,r+l,1,_-h))
如果记录:
打印“正在返回的候选人:%s”%s
返回候选人
#正确的字符是任意的,但是
#前一个字符必须与前一个字符匹配。
如果i==len(父母)-1:
l=cs[len(cs)-2][1]
如果记录:
打印“最右边的字符:%s”%l
如果len(selected[i])<2或(selected[i]中没有l):
如果记录:
打印“未找到匹配项:len(所选[i])<2或(所选[i]中没有l])”
返回[]
其他:
结果=[]
对于[x]中的r,对于所选[i]中的x,如果x!=l],则为keys():
_cs=深度复制(cs)
_cs[len(cs)-2][2]=_cs[len(cs)-2][2]+1
_cs[len(cs)-1]=[1,r,1]
_s=s[:]+[选择的[i][l],选择的[i][r]]
结果.追加((_cs,_s,seq+l+r))
返回结果
父母=父母[i]
如果记录:
打印“获取候选项:g:父项,i:%s,%s”%(pa
                     B
            /                 \
          A                     O
      /       \             /       \   
     I        (R)         (R)        N
    / \       / \         / \       / \
   T  (N)   (N)  E      (N)  E     E   D
  V W W X   W X X Y     W X X Y   X Y Y Z

4 W's, 6 X's, 4 Y's 
    b
   a u
  l n r
 l d g s
o y s a e
    b
   a ?
  l ? ?
 l ? ? ?
o ? ? ? ?
    b
   a u
  l ? r
 l ? ? k
o ? ? ? e