この問題は、再帰バックトラッキングと呼ばれるもので解決できます。仮定を立ててから、文字列を解読するか、矛盾に達するまでその道を進みます。矛盾に達すると失敗が返され、呼び出し元の関数は次の可能性を試します。成功を返す場合は、呼び出し元に成功を返します。
申し訳ありませんが、これを解決しようとすることに抵抗できませんでした。これが私が思いついたものです:
# Define constants for even/odd/notset so we can use them in a list of
# assumptions about parity.
even = 0
odd = 1
notset = 2
# Define success and failure so that success and failure can be passed
# as a result.
success = 1
failure = 0
def tryParity(i, cipher, a, parities, parityToSet):
newParities = list(parities)
for j, p in parityToSet:
try:
if parities[j] == notset:
newParities[j] = p
elif parities[j] != p:
# Failure due to contradiction.
return failure, []
except IndexError:
# If we get an IndexError then this can't be a valid set of values for the parity.
# Error caused by a bad value for "a".
return failure, []
# Update "a" based on parity of i
new_a = a+1 if newParities[i] == even else a-1
return findParities(i+1,cipher,new_a,newParities)
def findParities(i, cipher, a, parities):
# Start returning when you've reached the end of the cipher text.
# This is when success start bubbling back up through the call stack.
if i >= len(cipher):
return success, [parities] # list of parities
# o stands for the index of the other char that would have been XORed.
# "o" for "other"
o = i+a if i + a < len(cipher)-1 else a
result = None
resultParities = []
toTry = []
# Determine if cipher[index] is even or odd
if ord(cipher[i]) % 2 == 0:
# Try both even and both odd
toTry = (((i,even),(o,even)),
((i,odd),(o,odd)))
else:
# Try one or the other even, one or the other odd
toTry = (((i,odd),(o,even)),
((i,even),(o,odd)))
# Try first possiblity, if success add parities it came up with to result
resultA, resultParA = tryParity(i, cipher, a, parities, toTry[0])
if resultA == success:
result = success
resultParities.extend(resultParA)
# Try second possiblity, if success add parities it came up with to result
resultB, resultParB = tryParity(i, cipher, a, parities, toTry[1])
if resultB == success:
result = success
resultParities.extend(resultParB)
return result, resultParities
def decrypt(cipher):
a = 10
parities = list([notset for _ in range(len(cipher))])
# When done, possible parities will contain a list of lists,
# where the inner lists have the parity of each character in the cipher.
# Comes back with mutiple results because each
result, possibleParities = findParities(0,cipher,a,parities)
# A print for me to check that the parities that come back match the real parities
print(possibleParities)
print(list(map(lambda x: 0 if ord(x) % 2 == 0 else 1, "this is a test string")))
# Finally, armed with the parities, decrypt the cipher. I'll leave that to you.
# Maybe more recursion is needed
# test call
decrypt(encrypt("this is a test string"))
うまくいくようですが、他の入力では試していません。
このソリューションでは、パリティのみが提供されます。文字の復号化はあなたに任せました。それらはおそらく一緒に行うことができますが、私はあなたの質問に答えることに集中したかったのです。私がインストールしたものなので、Python 3を使用しました。
この分野も初心者です。ピーター・ノーヴィグの本を読むことをお勧めします。難しい質問をありがとう。