隐身踢球者//


12

隐身踢

加密文本的一种常见但不安全的方法是置换字母。换句话说,字母表中的每个字母在文本中始终被其他字母替换。为确保加密是可逆的,同一字母不会替换任何两个字母。您的任务是解密几行编码的文本,假设每一行使用不同的替换集,并且解密的文本中的所有单词均来自已知单词的词典。

输入值

输入由小写字母组成,按字母顺序。这些单词构成了可能出现在解密文本中的单词词典。在字典之后是几行输入。每行如上所述进行加密。

词典中的单词数不超过1,000。没有一个单词超过16个字母。加密的行仅包含小写字母和空格,并且长度不超过80个字符。

输出量

解密每一行并将其打印到标准输出。如果有多种解决方案,那么任何一种都可以。如果没有解决方案,请用星号替换字母表中的每个字母。

样本输入

and dick jane puff spot yertle

bjvg xsb hxsn xsb qymm xsb rqat xsb pnetfn
xxxx yyy zzzz www yyyy aaa bbbb ccc dddddd

样本输出

dick and jane and puff and spot and yertle
**** *** **** *** **** *** **** *** ******

是解决方案。请注意,我不是争夺最短字节的竞争者/竞争性程序员。我只是喜欢拼图!

来源


1
请放宽您的> input <约束,以适用于每种语言。例如,很多语言会讨厌,并且不喜欢格式以6开头。我建议完全不指定格式,只说输入是单词列表和要加密的行列表。
orlp

好吧,你去!
Dhruv Ramani 2015年

1
是否有运行时限制?我是否可以简单地遍历所有可能的替换组合,直到完成一项工作(这可能需要数年才能完成)?
弥敦道·美林

@NathanMerrill这样做,如果要花费数年,只需以星号形式打印即可。Vihan,这不是重复的,请正确阅读问题。
Dhruv Ramani 2015年

我们可以只输出单词还是必须加入它们?
Downgoat,2015年

Answers:


3

Python 3,423个字节

import sys,re
S=re.sub
D,*L=sys.stdin.read().split('\n')
def f(W,M=[],V="",r=0):
 if len({d for(s,d)in M})==len(M):
  if[]==W:return V.lower()
  for d in D.split():p='([a-z])(?%s.*\\1)';m=re.match(S(p%'=',')\\1=P?(',S(p%'!',').>\\1<P?(',W[0].translate(dict(M))[::-1]))[::-1]+'$',d.upper());r=r or m and f(W[1:],M+[(ord(s),m.group(s))for s in m.groupdict()],V+d+" ")
  return r
for l in L:print(f(l.split())or S('\w','*',l))

使用与样本输入/输出相同的格式,从STDIN读取输入并将输出写入STDOUT。

说明

对于每行密文,我们执行以下过程:

我们保留已经建立的所有字母转换的地图M(最初为空)。我们这样做的方式是,源字母全为小写,目标字母全为大写。

我们按顺序处理密文中的单词。对于每个单词,我们在字典中找到所有可能匹配的单词,如下所示:

假设我们的单词wglpplppljjl并且M包含规则j -> P。我们首先使用M中的现有规则对w进行变换,得到。然后,我们将w转换为以下python风格的正则表达式:glpplpplPPl

(?P<g>.)(?P<l>.)(?P<p>.)(?P=p)(?P=l)(?P=p)(?P=p)(?P=l)PP(?P=l)

转换规则如下:

  • 每个小写字母的第一个出现x用替换。这定义了一个名为的捕获组,该捕获组与单个cahracter匹配。(?P<x>.)x
  • 每次后续出现时,每个小写字母x都将替换为。这是对命名组预先捕获的字符的反向引用。(?P=x)x

我们通过反转w,然后应用以下两个正则表达式替换来执行此转换:

s/([a-z])(?!.*\1)/)>\1<P?(/
s/([a-z])(?=.*\1)/)\1=P?(/

然后反转结果。请注意,先前由M转换的字符显示为大写,因此保持不变。

我们将结果正则表达式与每个字典单词匹配,其中字典单词以大写形式出现。例如,上述正则表达式将匹配单词MISSISSIPPI。如果找到匹配项,则从中提取新的转换规则,并将其添加到M中。新的转换规则只是每个捕获组捕获的字符。在上面的正则表达式中,分组g匹配M,分组l匹配I和分组p匹配S为我们提供了规则g -> M, l -> I, p -> S。我们必须确保产生的规则是一致的,也就是说,没有两个源字母映射到相同的目标字母。否则,我们拒绝比赛。

然后,我们使用增强的转换规则进入下一个单词。如果使用此过程可以匹配所有密文单词,则我们已经解密了文本。如果我们无法将单词与任何词典单词进行匹配,我们将回溯并尝试将先前的单词与不同词典单词进行匹配。如果此过程失败,则没有解决方案,我们将打印一行星号。


2

CJam,62 56字节

qN%Sf/(f{\:C,m*{C..+`Sa`m2/Q|z_''f-Qf|=},C:,'*f*a+0=S*N}

速度很慢,而且内存很饿,但是可以与Java解释器一起用于测试用例。

运行示例

$ cat input; echo
and dick jane puff spot yertle

bjvg xsb hxsn xsb qymm xsb rqat xsb pnetfn
xxxx yyy zzzz www yyyy aaa bbbb ccc dddddd
$ time cjam kicker.cjam < input
dick and jane and puff and spot and yertle
**** *** **** *** **** *** **** *** ******

real    5m19.817s
user    6m41.740s
sys     0m1.611s
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.