Skip to content

19960: 恩尼格玛

http://cs101.openjudge.cn/practice/19960/

Frank老师在计算概论的第一堂课上让同学们观看了“模仿游戏”这部电影。看完以后,Hitler同学对其中的恩尼格玛加密机产生了浓厚的兴趣。在网上查阅资料以后,他决定从简单的情况入手(输入文本只包含abcdef六个字母),用电脑实现一个恩尼格玛加密机。 加密机的原理如下(参照示意图):

img

三个转子上都有线路,彼此相连;反射器将六个槽位两两相连;输入某一字母后经过左中右三个转子到达反射器,再返回,依次通过右中左三个转子,最后得到加密字母(全小写)。(如图中,输入b得到d)

注意:每输入一个字母,左边的转子都会向下转一位,左边的转子转了一圈以后中间的转子向下转一位,中间的转子转一圈以后最右边的转子向下转一位

输入

前18行,每行2个数字,以空格隔开,表示转子进出的初始线路连接(1-6行是左转子,7-12行是中间转子,13-18行是右转子) 第19-21行,每行2个数字,以空格隔开,表示反射器中两两连接的情况 最后一行是待加密的字符串(只含有abcdef六个字母,全小写)

输出

加密后的字符串(全小写)

样例输入

1 6
2 3
3 5
4 4
5 2
6 1
1 3
2 1
3 4
4 2
5 6
6 5
1 5
2 1
3 4
4 6
5 3
6 2
1 6
2 3
4 5
abcdefabcdefabcdef

样例输出

caecaeccbffefdabbc

解释:处理完第一个字符'a'以后,左转子变为(2 1;3 4;4 6;5 5;6 3;1 2),
中间转子、右转子不变

来源

cs101-2019 张昊骞

相当于左转子向下转一次后,行标号均加一 (1 6 -> 2 7(2 1)); (2 3 -> 3 4)

字母a,始终找左转子的第一行,但是经过之前左转子向下转一位,第一行会被原来的第六行替代,此时左转子第一行线路是(1 2)。它由第六行的 6 1 -> 1 2而来。如果能明白输入ab,输出ca应该能明白了。

python
def rotate(a):
    return (a % 6) + 1  # 返回加1后的结果,自动回绕到1

def update_rotation(dic):
    return {rotate(k): rotate(v) for k, v in dic.items()}  # 一次性更新字典

# 初始化字典
rotL, rotM, rotR = {}, {}, {}
rerotL, rerotM, rerotR = {}, {}, {}
ref, alpha = {}, {}

# 读取输入并初始化旋转字典
for i in range(6):
    come, go = map(int, input().split())
    rotL[come] = go
    rerotL[go] = come

for i in range(6):
    come, go = map(int, input().split())
    rotM[come] = go
    rerotM[go] = come

for i in range(6):
    come, go = map(int, input().split())
    rotR[come] = go
    rerotR[go] = come

# 读取参考交换字典
for i in range(3):
    come, go = map(int, input().split())
    ref[come] = go
    ref[go] = come

# 字母到数字的映射和反向映射
for i in ['a', 'b', 'c', 'd', 'e', 'f']:
    alpha[i] = ord(i) - 96
    alpha[ord(i) - 96] = i

# 处理输入字符串
string = list(input())
output = []
time = 0

for i in string:
    code = alpha[i]
    # 执行多次旋转操作并存入输出列表
    output.append(alpha[rerotL[rerotM[rerotR[ref[rotR[rotM[rotL[code]]]]]]]])

    # 更新字典
    rotL = update_rotation(rotL)
    rerotL = update_rotation(rerotL)
    time += 1

    # 每6次旋转更新 rotM, rerotM
    if time % 6 == 0:
        rotM = update_rotation(rotM)
        rerotM = update_rotation(rerotM)

    # 每36次旋转更新 rotR, rerotR
    if time % 36 == 0:
        rotR = update_rotation(rotR)
        rerotR = update_rotation(rerotR)

# 输出最终加密后的字符串
print(''.join(output))
python
def rotate(a):
    return (a % 6) + 1  # 返回加1后的结果,自动回绕到1

def update_rotation(dic):
    return {rotate(k): rotate(v) for k, v in dic.items()}  # 一次性更新字典

# 初始化字典
rotL, rotM, rotR = {}, {}, {}
rerotL, rerotM, rerotR = {}, {}, {}
ref, alpha = {}, {}

# 读取输入并初始化旋转字典
for i in range(6):
    come, go = map(int, input().split())
    rotL[come] = go
    rerotL[go] = come

for i in range(6):
    come, go = map(int, input().split())
    rotM[come] = go
    rerotM[go] = come

for i in range(6):
    come, go = map(int, input().split())
    rotR[come] = go
    rerotR[go] = come

# 读取参考交换字典
for i in range(3):
    come, go = map(int, input().split())
    ref[come] = go
    ref[go] = come

# 字母到数字的映射和反向映射
for i in ['a', 'b', 'c', 'd', 'e', 'f']:
    alpha[i] = ord(i) - 96
    alpha[ord(i) - 96] = i

# 处理输入字符串
string = list(input())
output = []
time = 0

for i in string:
    code = alpha[i]
    # 执行多次旋转操作并存入输出列表
    output.append(alpha[rerotL[rerotM[rerotR[ref[rotR[rotM[rotL[code]]]]]]]])

    # 更新字典
    rotL = update_rotation(rotL)
    rerotL = update_rotation(rerotL)
    time += 1

    # 每6次旋转更新 rotM, rerotM
    if time % 6 == 0:
        rotM = update_rotation(rotM)
        rerotM = update_rotation(rerotM)

    # 每36次旋转更新 rotR, rerotR
    if time % 36 == 0:
        rotR = update_rotation(rotR)
        rerotR = update_rotation(rerotR)

# 输出最终加密后的字符串
print(''.join(output))