弦乐建设游戏的制胜策略


14

背景

爱丽丝和鲍勃玩的游戏叫构造二进制字。要玩游戏,您需要确定一个长度n >= 0,一G组长度为n二进制的单词(称为目标集)和一个长度n字符串(t其中包含字母Aand)B,称为回合顺序。游戏持续进行n几回合,然后依次选择i定义的玩家。游戏结束后,玩家将查看他们构建的二进制单词。如果在目标组中找到了这个词,爱丽丝将赢得比赛;否则,鲍勃获胜。t[i]w[i]wG

例如,让我们来解决n = 4G = [0001,1011,0010]t = AABA。爱丽丝得到第一回合,她选择了w[0] = 0。第二轮也是爱丽丝的,她选择w[1] = 0。鲍勃第三回合,他选择了w[2] = 0。在最后一圈,爱丽丝选择w[3] = 1。结果字词,0001在中找到G,因此爱丽丝赢得了比赛。

现在,如果鲍勃选择了w[2] = 1,爱丽丝本可以w[3] = 0在最后一轮选择,但仍然获胜。这意味着无论Bob如何玩,Alice都能赢得比赛。在这种情况下,爱丽丝有一个制胜法宝。可以将这种策略可视化为标记的二叉树,该树在与Bob的转弯相对应的级别上分支,并且其每个分支都包含来自的单词G

A A B A

-0-0-0-1
    \
     1-0

爱丽丝在转弯时只跟随树枝而玩;无论鲍勃选择哪个分支,爱丽丝最终都会获胜。

输入值

输入为length n,集合G为length的字符串列表(可能为空)n

输出量

您的输出是Alice拥有获胜策略的周转单列表,这等效于如上所述的二叉树的存在。周转单的顺序无关紧要,但禁止重复。

详细规则

您可以编写完整的程序或函数。对于程序,您可以为输入和输出选择定界符,但两者必须相同。最短的字节数获胜,并且不允许出现标准漏洞。

测试用例

3 [] -> []
3 [000,001,010,011,100,101,110,111] -> [AAA,AAB,ABA,ABB,BAA,BAB,BBA,BBB]
4 [0001,1011,0010] -> [AAAA,BAAA,AABA]
4 [0001,1011,0010,0110,1111,0000] -> [AAAA,BAAA,ABAA,BBAA,AABA,AAAB]
5 [00011,00110,00111,11110,00001,11101,10101,01010,00010] -> [AAAAA,BAAAA,ABAAA,BBAAA,AABAA,AAABA,BAABA,AAAAB,AABAB]

有趣的事实

输出中的转弯单数始终等于目标集中的单词数。


5
输入和输出大小相等,这让我很感兴趣。您是否对此事实有证据或引证?我想知道是否有一种方法可以直观地保留大小来计算此函数。
xnor

2
您的测试案例#5与您的有趣事实相矛盾...
mbomb007'1

3
@ mbomb007测试案例5列出了11101两次;有趣的事实仍然适用。Zgarb,输入内容可能包含重复的元素,还是这是一个错误?
xnor

@xnor这是我前一段时间研究中提出的。我在第16页的预印本中有一个证明,但实际上与您的相同。
Zgarb 2015年

1
@xnor凭直觉,无论如何,如果0和1都是获胜的选择,那么Alice或Bob都可以选择下一步。如果只有一个获胜选项,那么爱丽丝必须选择下一个。因此,字符串的选择次数与获胜策略的选择次数相同。不太严格,但是引人注目。
Alchymist 2015年

Answers:


1

Dyalog APL,59个字节

{(a≡,⊂⍬)∨0=⍴a←∪⍵:a⋄(∇h/t)(('A',¨∪),'B',¨∩)∇(~h←⊃¨a)/t←1↓¨a}

与@xnor解决方案中的算法相同。

(a≡,⊂⍬)∨0=⍴a←∪⍵:a
           a←∪⍵    ⍝ "a" is the unique items of the argument
        0=⍴a       ⍝ is it empty?
 a≡,⊂⍬             ⍝ is it a vector that contains the empty vector?
       ∨       :a  ⍝ if any of the above, return "a"

(∇h/t)(('A',¨∪),'B',¨∩)∇(~h←⊃¨a)/t←1↓¨a
                                 t←1↓¨a  ⍝ drop an item from each of "a" and call that "t"
                         ~h←⊃¨a          ⍝ first of each of "a", call that "h", then negate it
                                /        ⍝ use "~h" as a boolean mask to select from "t"
                       ∇                 ⍝ apply a recursive call
(∇h/t)                                   ⍝ use "h" as a boolean mask on "t", then a recursive call
      (('A',¨∪),'B',¨∩)                  ⍝ apply a fork on the results from the two recursive calls:
       ('A',¨∪)                          ⍝   prepend 'A' to each of the intersection
               ,                         ⍝   concatenated with
                'B',¨∪                   ⍝   prepend 'B' to each of the union

13

巨蟒,132

def f(S,n):
 if n<1:return S
 a,b=[f({x[1:]for x in S if x[0]==c},n-1)for c in'01']
 return{'A'+y for y in a|b}|{'B'+y for y in a&b}

示例运行:

f({'000','001','010','011','100','101','110','111'},3) == 
{'ABA', 'ABB', 'AAA', 'AAB', 'BBB', 'BBA', 'BAB', 'BAA'}

这只是打高尔夫球,主要是为了展示算法。输入和输出是字符串集。Python似乎没有正确的功能来紧凑地表达其部分内容,因此,如果有人用更适合的语言编写此代码,那会很酷。

这是数学上可以表示递归的方式。不幸的是,PPCG仍然缺乏数学渲染功能,因此我必须使用代码块。

感兴趣的对象是字符串集。让|代表集合联合,&代表集合相交。

如果c是字符,则让c#S将该字符c放在之前的所有字符串中S。相反,让收缩c\SS紧跟在初始字符之后的单字符短字符串c,例如0\{001,010,110,111} = {01,10}

我们可以S按字符01的第一个字符唯一地分割一组带有char 的字符串。

S = 0#(0\S) | 1#(1\S)

然后,我们可以f如下表示所需的函数,在前两行中使用基数情况,在最后一行中使用递归罐:

f({})   = {}
f({''}) = {''}
f(S)    = A#(f(0\S)|f(1\S)) | B#(f(0\S)&f(1\S))

请注意,我们不需要使用length n

为什么这样做?让我们考虑一下让Alice赢得一组字符串的移动字符串S

如果第一个字符是A,则Alice可以选择第一个动作(“ 0”或“ 1”),让她选择将问题减少为S0S1。因此,现在剩余的移动字符串必须至少位于f(S0)或中之一f(S1),因此我们采用它们的并集|

同样,如果第一个字符为“ B”,则Bob会选择,Bob会为Alice选择较差的一个,因此其余的移动字符串必须在交点(&)中。

基本案例只需检查最后是否S为空。如果我们要跟踪字符串的长度,则n每次递归时都减去1,则可以写基数:

f(S) = S if n==0

递归解决方案还说明f(S)了与大小相同的有趣事实S。对于基本情况和归纳情况都是如此

f(S) = A#(f(0\S)|f(1\S)) | B#(f(0\S)&f(1\S))

我们有

size(f(S)) = size(A#(f(0\S)|f(1\S)) | B#(f(0\S)&f(1\S)))
           = size(A#(f(0\S)|f(1\S))) + size(B#(f(0\S)&f(1\S))))
           = size((f(0\S)|f(1\S))) + size((f(0\S)&f(1\S))))
           = size(f(0\S)) + size(f(1\S))  [since size(X|Y) + size(X&Y) = size(X) + size(Y)]
           = size(0\S) + size(1\S)
           = size(S)

运行代码即可TypeError: 'int' object is not subscriptable。您是否有可运行程序的链接?我只是将其粘贴并与一起运行print f([0001,1011,0010],4)
mbomb007

@ mbomb007该功能需要像一样调用f({'000','001','010','011','100','101','110','111'},3)。这样会出错吗?
xnor

啊,我没看到我缺少引号,谢谢。它也与print f(['0001','1011','0010'],4)
mbomb007

如果您想运行n独立于参数的程序,它将是n=len(S[0])if S!=[]else 0
mbomb007'1

在此处运行:repl.it/7yI
mbomb007
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.