我如何解决"Crypt踢球"运动提议在"编程的挑战(编程竞赛的培训手册)"?

StackOverflow https://stackoverflow.com/questions/2175356

  •  24-09-2019
  •  | 
  •  

"编程的挑战(编程竞赛的培训手册)"可能是一个最好的练习簿上的算法。我已经解决的第11个练习,但是我现在坚持与"Crypt踢球"问题:

墓穴踢球
一个常见,但不安全的方法进行加密的文本是重排的字母表中的字母。换句话说,每一个字母表中的字母是一致的替代案文通过一些其他的信。为确保密是可逆的,没有两个字母替换成相同的信。

你的任务是解密的几个编码的行文本,假设每个线使用一套不同的替代品,所有词语的解密的文本是从字典中已知的话。

输入
输入由一个包含整数n,随后通过n个小写的话说,每条线,按字母顺序排列。这些n话撰写的字典的话中可能出现的被解密的文本。
以下字典中的几行的输入。每个线是加密的,如上所述。

有没有1 000多词在字典中。没有字超过16 字母。加密的线路只包含下情况的信和空间 没有超过80个字符长。

输出
解每个线和打印标准输出。如果有多个解决方案,任何一个人会做。
如果没有解决方案,替代的每一个字母通过一个星号。

样本输入 6

迪克
jane
粉扑

yertle

bjvg xsb hxsn xsb qymm xsb rqat xsb pnetfn
xxxx yyy zzzz www年aaa往ccc dddddd

样本输出
迪克和简和粉扑点和yertle...

什么样的 战略 我应该采取为了解决这个运动?我想到一个经典的和野蛮的回溯的解决方案,但是我想避免这直到我找到的东西更加智能化。

PS:这不是家庭作业有关,我只是想提高我的总体技能。

有帮助吗?

解决方案

KeyArray将举行的替代表。

  • 启动一个空KeyArray,这是0版本

  • 比赛最长的加密词来最长的字典字,并添加到KeyArray (如果存在两个最长,挑选任何),这是版本1。

  • 解密的一些信函的下一个长加密的话。

  • 检查是否已解密的字母匹配的字母相同 位置中的任何词典词的长度相同。
  • 如果没有匹配,回到版0,并尝试另一个词。
  • 如果有些字母匹配,加入其余的字母KeyArray,这是第2版。

  • 解密的一些信函的下一个长加密的话。

  • 检查是否已解密的字母匹配的字母相同 位置中的任何词典字。
  • 如果没有匹配,回到第1版,并尝试另一个词
  • 如果有些字母匹配,加入其余的字母KeyArray,这是版本3。

重复,直到所有的话都是解密。

如果在版0没有时间最长的单词创造一个部分解中 较短的话,很可能没有解决方案。

其他提示

一个次要优化可以通过回溯运行之前列举的可能实现。在Python:

dictionary = ['and', 'dick', 'jane', 'puff', 'spot', 'yertle']
line = ['bjvg', 'xsb', 'hxsn', 'xsb', 'qymm', 'xsb', 'rqat', 'xsb', 'pnetfn']

# ------------------------------------

import collections

words_of_length = collections.defaultdict(list)

for word in dictionary:
  words_of_length[len(word)].append(word)

possibilities = collections.defaultdict(set)
certainities = {}

for word in line:
    length = len(word)
    for i, letter in enumerate(word):
        if len(words_of_length[length]) == 1:
            match = words_of_length[length][0]
            certainities[letter] = match[i]
        else:
            for match in words_of_length[length]:
              possibilities[letter].add(match[i])

for letter in certainities.itervalues():
    for k in possibilities:
        possibilities[k].discard(letter)

for i, j in certainities.iteritems():
    possibilities[i] = set([j])

# ------------------------------------

import pprint
pprint.pprint(dict(possibilities))

输出:

{'a': set(['c', 'f', 'o']),
 'b': set(['d']),
 'e': set(['r']),
 'f': set(['l']),
 'g': set(['f', 'k']),
 'h': set(['j', 'p', 's']),
 'j': set(['i', 'p', 'u']),
 'm': set(['c', 'f', 'k', 'o']),
 'n': set(['e']),
 'p': set(['y']),
 'q': set(['i', 'j', 'p', 's', 'u']),
 'r': set(['j', 'p', 's']),
 's': set(['n']),
 't': set(['t']),
 'v': set(['c', 'f', 'o']),
 'x': set(['a']),
 'y': set(['i', 'p', 'u'])}

如果你有一些单元素的可能性,则可以从输入消除它们并重新运行的算法。

修改:切换到集合而不是列表,并加入打印代码

我真的试图相当不同的方法。我内置从字典单词的线索。然后,我通过线索和句子一起递归(运行在DFS特里树)行走。

在每个空间都一定打在一个线索字的末尾,如果是我循环返回到根。一路上我跟踪号分配到目前为止,我所做的。如果说我有一个分配违背先前的任务,我会失败,并解开递归点我可以让下一个可能的分配新建分配FY。

这听起来很棘手,但它似乎工作得很好。它是真的并不难代码了!

另一个可能的优化,如果你有“足够”的文字处理,你知道该文本的语言,你可以使用字母频率(见:http://en.wikipedia.org/wiki/Letter_frequency)。 6/7万字打交道时,但会以最快的方式,如果你有几页解码这当然是一个非常近似的方法。

编辑:关于最大的解决方案,你可以尝试提取词的一些特点,也如重复的字母。显然,陈述说粉扑在密文字典和qymm与双信结束只有四个字母的单词给出的字母3直接的答案。在更复杂的情况下,你应该能够缩小的可能性,每个字母的夫妇。

这里是一个Java实现更多改进的 算法 拟议的通过@卡洛斯*古铁雷斯.

墓穴的起脚算法和解决方案,什么错了?

  • 改进是增加一个字图,以减少搜索空间的对话。例如,词语"abc"和"她"具有相同的模式,而"aac"和"她"不作为三种不同的字母的词会不匹配的一辆拖字母,不同的词。

  • 此外,算法可以实现递归其是更为直观和合理的。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top