我试图编写一个模仿文字游戏的程序,从一组给定的单词中,它会找到最长的单词序列。没有任何一个词可以使用两次。
我可以完成匹配的字母和单词,并将它们存储到列表中,但是我无法理解如何处理列表中潜在指数的单词可能性。如果单词1与单词2匹配然后我沿着那条路走下去,那么我如何备份以查看单词3或4是否与单词1匹配然后开始他们自己的路由,所有这些都来自第一个单词?
我在考虑某种方式调用内部函数可能吗?
我知道它无法完成我需要做的事情,但这只是一个开始。在此先感谢您的帮助!
g = "audino bagon baltoy banette bidoof braviary bronzor carracosta charmeleon cresselia croagunk darmanitan deino emboar emolga exeggcute gabite girafarig gulpin haxorus"
def pokemon():
count = 1
names = g.split()
first = names[count]
master = []
for i in names:
print (i, first, i[0], first[-1])
if i[0] == first[-1] and i not in master:
master.append(i)
count += 1
first = i
print ("success", master)
if len(master) == 0:
return "Pokemon", first, "does not work"
count += 1
first = names[count]
pokemon()
答案 0 :(得分:3)
你在内部调用函数的想法很好。我们可以通过递归来解决这个问题:
def get_neighbors(word, choices):
return set(x for x in choices if x[0] == word[-1])
def longest_path_from(word, choices):
choices = choices - set([word])
neighbors = get_neighbors(word, choices)
if neighbors:
paths = (longest_path_from(w, choices) for w in neighbors)
max_path = max(paths, key=len)
else:
max_path = []
return [word] + max_path
def longest_path(choices):
return max((longest_path_from(w, choices) for w in choices), key=len)
现在我们只定义单词列表:
words = ("audino bagon baltoy banette bidoof braviary bronzor carracosta "
"charmeleon cresselia croagunk darmanitan deino emboar emolga "
"exeggcute gabite girafarig gulpin haxorus")
words = frozenset(words.split())
使用一组字词致电longest_path
:
>>> longest_path(words)
['girafarig', 'gabite', 'exeggcute', 'emolga', 'audino']
要了解的一些事项:正如您所指出的,这具有指数级的复杂性,所以要小心!另外,知道python有一个递归限制!
答案 1 :(得分:2)
使用一些黑魔法和图论我发现了一个可能很好的部分解决方案(未经过彻底测试)。
我们的想法是将您的问题映射到图形问题而不是简单的迭代问题(尽管它也可能有用!)。所以我将图形的节点定义为单词的第一个字母和最后一个字母。我只能在first
和last
类型的节点之间创建边。我无法将节点first
数字X映射到节点last
数字X(单词不能自己跟随)。从那以后你的问题就像the Longest path problem一样,在一般情况下往往是NP难的:)
在此处提供一些信息:stackoverflow-17985202我设法写了这个:
g = "audino bagon baltoy banette bidoof braviary bronzor carracosta charmeleon cresselia croagunk darmanitan deino emboar emolga exeggcute gabite girafarig gulpin haxorus"
words = g.split()
begin = [w[0] for w in words] # Nodes first
end = [w[-1] for w in words] # Nodes last
links = []
for i, l in enumerate(end): # Construct edges
ok = True
offset = 0
while ok:
try:
bl = begin.index(l, offset)
if i != bl: # Cannot map to self
links.append((i, bl))
offset = bl + 1 # next possible edge
except ValueError: # no more possible edge for this last node, Next!
ok = False
# Great function shamelessly taken from stackoverflow (link provided above)
import networkx as nx
def longest_path(G):
dist = {} # stores [node, distance] pair
for node in nx.topological_sort(G):
# pairs of dist,node for all incoming edges
pairs = [(dist[v][0]+1,v) for v in G.pred[node]]
if pairs:
dist[node] = max(pairs)
else:
dist[node] = (0, node)
node,(length,_) = max(dist.items(), key=lambda x:x[1])
path = []
while length > 0:
path.append(node)
length,node = dist[node]
return list(reversed(path))
# Construct graph
G = nx.DiGraph()
G.add_edges_from(links)
# TADAAAA!
print(longest_path(G))
虽然它看起来不错,但有一个大缺点。您的示例有效,因为输入字的结果图中没有循环,但是,此解决方案在循环图上失败。 解决这个问题的方法是检测循环并打破它们。检测可以这样做:
if nx.recursive_simple_cycles(G):
print("CYCLES!!! /o\")
可以通过在循环中删除随机边缘来完成循环,然后您将随机找到问题的最佳解决方案(想象一个带尾部的循环,您应该在具有3个边缘的节点上切割循环)因此,我建议通过尝试所有可能的循环中断,计算最长路径并采用最长路径中的最长路径来强制执行此部分。如果你有多个循环,那么它的可能性就会变得更具爆炸性......但是它是NP难的,至少我看到它的方式并且我现在不打算解决这个问题:)
希望有所帮助
答案 2 :(得分:0)
这是一个不需要递归的解决方案。它使用itertools permutation function来查看单词的所有可能排序,并找到长度最长的单词。为了节省时间,一旦订单点击不起作用的单词,它就会停止检查排序并继续前进。
>>> g = 'girafarig eudino exeggcute omolga gabite'
... p = itertools.permutations(g.split())
... longestword = ""
... for words in p:
... thistry = words[0]
... # Concatenates words until the next word doesn't link with this one.
... for i in range(len(words) - 1):
... if words[i][-1] != words[i+1][0]:
... break
... thistry += words[i+1]
... i += 1
... if len(thistry) > len(longestword):
... longestword = thistry
... print(longestword)
... print("Final answer is {}".format(longestword))
girafarig
girafariggabiteeudino
girafariggabiteeudinoomolga
girafariggabiteexeggcuteeudinoomolga
Final answer is girafariggabiteexeggcuteeudinoomolga
答案 3 :(得分:0)
首先,让我们看看问题是什么:
from collections import defaultdict
import pydot
words = (
"audino bagon baltoy banette bidoof braviary bronzor carracosta "
"charmeleon cresselia croagunk darmanitan deino emboar emolga "
"exeggcute gabite girafarig gulpin haxorus"
).split()
def main():
# get first -> last letter transitions
nodes = set()
arcs = defaultdict(lambda: defaultdict(list))
for word in words:
first = word[0]
last = word[-1]
nodes.add(first)
nodes.add(last)
arcs[first][last].append(word)
# create a graph
graph = pydot.Dot("Word_combinations", graph_type="digraph")
# use letters as nodes
for node in sorted(nodes):
n = pydot.Node(node, shape="circle")
graph.add_node(n)
# use first-last as directed edges
for first, sub in arcs.items():
for last, wordlist in sub.items():
count = len(wordlist)
label = str(count) if count > 1 else ""
e = pydot.Edge(first, last, label=label)
graph.add_edge(e)
# save result
graph.write_jpg("g:/temp/wordgraph.png", prog="dot")
if __name__=="__main__":
main()
结果
这使解决方案相当明显(路径显示为红色),但仅仅因为图形是非循环的(除了两个平凡的自循环)。