我有一个数字[1,2,3,4,5,6,7,8,9,10]
的列表,现在我用它们组合了一些。我们说[2,2,4,5,1,1]
。
现在程序必须猜测我的想法是什么组合
然后程序将生成一个与我的组合长度相同的随机列表。比方说,它将是[1,2,5,5,4,3]
。
现在我必须告诉正确位置有多少个数字,哪些数字正确但位置错误。因此,在这种情况下正确的是两个数字(2和5)。 1和3也正确但在错误的地方。
最初,程序应该使用我的提示猜测密码。有人可以帮我弄清楚或给出用于解决此类问题的算法的提示。
答案 0 :(得分:0)
这应该可以帮助你开始。以下代码将有助于生成由1到10之间的数字组成的随机组合
from random import randrange
# randrange will generate a random number between 1 and 11
# the end value 11 is not included
# for _ in range(0, 6) is used to iterate 6 times
comb = [randrange(1, 11) for _ in range(0, 6)]
答案 1 :(得分:0)
免责声明:此解决方案不适用于您的问题集大小,因为您的问题集是10 ^ 6,算法是二次的。二次部分是易于修复的部分(如果您不关心最佳解决方案),您不必考虑所有可能的猜测,它足以进行采样并测试样本是否足够好(例如:至少将国家空间减半。更难解决的一件事是状态空间的初始大小。您可以对一些初始猜测进行硬编码(例如,对前3个猜测进行硬编码),然后仅使用有效组合生成初始状态空间(例如:如果您发现板上没有'1',则不会生成猜测包含'1')。
以下是使用Knuth's minmax solution解决问题的代码。
我做了一个小修改(主要是为了简化代码和速度),以便只考虑下一个猜测的有效答案。因此,算法有时需要额外的步骤。
Knuth还举了一个例子,表明在某些情况下没有S的成员 将是最高得分的猜测之一,因此猜测不能 在下一回合获胜,但有必要确保五场胜利。
这是一个病态的例子:
Secret: [1, 1, 1, 0]
(0, 0, 1, 1) -> (1, 2)
(5, 1, 1, 0) -> (3, 0)
(4, 1, 1, 0) -> (3, 0)
(3, 1, 1, 0) -> (3, 0)
(2, 1, 1, 0) -> (3, 0)
(1, 1, 1, 0) -> (4, 0)
Done in 6 steps
它可以很容易地用较少的步骤找出缺失的颜色,但因为它只尝试有效的解决方案,所以需要一个额外的步骤。
#!/usr/bin/python
import random
import itertools
import collections
COLORS, PEGS = 6, 4
def random_secret():
return [random.randrange(COLORS) for _ in range(PEGS)]
def all_states():
return list(itertools.product(*[range(COLORS) for _ in range(PEGS)]))
def evaluate(secret, guess):
color_and_pos = 0
color = 0
colors = collections.defaultdict(int)
for i in range(len(secret)):
if secret[i] == guess[i]:
color_and_pos += 1
else:
colors[secret[i]] += 1
for i in range(len(secret)):
if secret[i] != guess[i]:
if colors[guess[i]] > 0:
colors[guess[i]] -= 1
color += 1
return (color_and_pos, color)
def list_count(l):
#for python >= 2.7 you can use collections.Counter
return dict((x, l.count(x)) for x in set(l))
def dict_max_value(d):
return max(d.values())
def minmax(fun, actions):
min, choice = None, None
for action in actions:
max = fun(action)
if choice is None:
min, choice = max, action
elif max <= min:
min, choice = max, action
return choice
class Algo():
def __init__(self):
self.contenders = all_states()
def initial_guess(self):
return tuple([0] * (PEGS/2) + [1] * (PEGS - PEGS/2))
def next_guess(self, qnas):
self.filter_contenders(qnas[-1])
#print "contenders size: ", len(self.contenders)
return minmax(lambda (candidate):
dict_max_value(list_count(
[evaluate(contender, candidate) for contender in self.contenders]
)), self.contenders)
def filter_contenders(self, qna):
self.contenders = [contender for contender in self.contenders
if evaluate(contender, qna[0]) == qna[1]]
class Game():
def __init__(self, algo):
self.algo = algo
def run(self):
secret = random_secret()
print "Secret:", secret
qnas = []
n = 1
guess = self.algo.initial_guess()
while True:
answer = evaluate(secret, guess)
qnas.append((guess, answer))
print guess, "->", answer
if answer == (PEGS, 0):
break
guess = self.algo.next_guess(qnas)
n += 1
print "Done in", n, "steps"
Game(Algo()).run()
答案 2 :(得分:0)
“然后程序将生成一个与我的组合长度相同的随机列表” - 这是问题的一部分吗?你后来说程序使用了你的提示,所以我假设你正在生成随机的数字列表,试图找出密码,同时只使用随机的数字列表而不是使用你所拥有的信息来做出更好的猜测,可以缩小结果更快。
在这种情况下,您需要跟踪您的猜测,并且每个人都要弄清楚您可以从中收集哪些信息。每当您从猜测中获得新信息时,您都可以返回先前猜测的结果,看看您是否获得任何新信息。对于你的例子,让我们说它是这样的,包括我在第一次之后的编制猜测:
PASSWORD: [2,2,4,5,1,1]
GUESS 1: [1,2,5,5,4,3] - 4 correct, 2 right position
GUESS 2: [5,2,1,7,3,8] - 3 correct, 1 right position
GUESS 3: [7,7,8,3,7,9] - 0 correct, 0 right position
GUESS 4: [5,6,5,3,8,9] - 1 correct, 0 right position
GUESS 5: [8,2,5,6,7,3] - 2 correct, 1 right position
猜测3后你知道你没有3s,7s,8s或9s。再回到你的第二个猜测,你知道其中三个是1,2,5,因为你没有3,7,8。用这些知识回到你的第一个猜测,你知道答案有1,2,5以及4或5.看第4个猜测你现在知道只有一个5,所以你的四个数字是1 ,2,4,5。继续使用此算法,直到找出所有6个数字,而不是关注它们的位置。
一旦你拥有了所有6个数字,你就可以切换算法来确定这些数字的位置。每次学习新信息时都要回顾以前的所有猜测,如果你遇到困难,继续猜测随机密码。对于初始运行,你知道5因为猜测而不在第一或第三位置。猜猜2 - 你知道5不在位置1,所以要么2或1位于正确的位置[X, 2,1,X,X,X]。猜猜1你知道5不在位置3,所以下面的2个位于正确的位置:[1,2,X,5,4,X]。猜猜5告诉你,2或者5位于正确的位置,但你知道5因为猜测4而处于错误的位置,所以现在你知道2位于位置2.将这些信息与猜测2结合起来告诉你不知道1不在第3位,所以你知道它必须是4或2。
表示你的知识的一种方法是为每个数字提供最小和最大计数的数组,以及每个数字的布尔数组,告诉你哪些数字可以去那里。获得所有可以猜测的信息后,您可以将其从列表中删除,这样您就不必再次查看了。因此,在猜测3之后,最大数量3,7,8,9为0.您还可以为每个位置设置这些可能性为假。这就是你可以得到的所有信息,所以你不必再看看猜猜3。
您也可以改变猜测以简化它,例如,一旦您知道2进入第2位并且没有3,7,8,您可以删除那些“知识”和猜测2更改:
GUESS 2: [5,2,1,7,3,8] - 3 correct, 1 right position
NEW 2: [5,X,1,X,X,X] - 2 correct, 0 right position
但是一旦你知道了所有的数字,并且对于位置3将5设置为false而对于位置3设置为1则为false,这不能为您提供更多信息,您可以从列表中删除此猜测。