“挑选数字游戏”的算法

时间:2011-11-11 15:56:21

标签: algorithm permutation puzzle

我很难找到解决办法,但我不知道。

RobotA和RobotB选择N个数字的排列开始。 RobotA首先选择,他们交替选择。每转一圈,机器人只能从排列中挑选任何一个剩余的数字。当剩余数字形成递增序列时,游戏结束。选择最后一个回合的机器人(之后序列变得越来越大)赢得了游戏。

假设两者都发挥得最好,谁赢了?

示例1:

 The original sequence is 1 7 3. 
 RobotA wins by picking 7, after which the sequence is increasing 1 3.

示例2:

 The original sequence is 8 5 3 1 2.
 RobotB wins by selecting the 2, preventing any increasing sequence.

有没有任何已知的算法可以解决这个问题?请给我任何关于在哪里看的提示或想法真的很感激!

4 个答案:

答案 0 :(得分:4)

给定不同数字的序列w,让N(w)w的长度,让L(w)w中增长最长的子序列的长度}。例如,如果

w = 3 5 8 1 4

然后N(w) = 5L(w) = 3

游戏在L(w) = N(w)时结束,或等同于N(w) - L(w) = 0

向后游戏,如果在RobotX的转弯N(w) - L(w) = 1,则最佳游戏是移除不在最长的子序列中的唯一字母,从而赢得游戏。

例如,如果w = 1 7 3,则N(w) = 3L(w) = 2具有最长的后续子序列为1 3。删除7会导致序列递增,确保删除7的玩家获胜。

回到上一个示例w = 3 5 8 1 4,如果删除了14,那么对于结果排列u我们有N(u) - L(u) = 1,因此,移除14的玩家肯定会输给有能力的对手。然而,任何其他比赛都会导致胜利,因为它迫使下一名球员进入失败位置。在这里,最佳游戏是移除358中的任何一个,之后N(u) - L(u) = 2,但在下一次移动N(v) - L(v) = 1之后。

沿着这些方向的进一步分析应该为任何一个球员带来最佳策略。


我所知道的最近的数学游戏是单调序列游戏。在单调序列游戏中,两个玩家交替地从一些固定有序集合中选择序列的元素(例如1,2,...,N)。当结果序列包含长度为A的升序子序列或长度为D的递减子序列时,游戏结束。这个游戏的起源是鄂尔多斯和Szekeres定理,在MONOTONIC SEQUENCE GAMES中可以找到一个很好的阐述,而Bruce Sagan的这个slide presentation也是一个很好的参考。

如果你想了解更多关于游戏理论的信息,或者特别是这些类型的游戏,那么我强烈推荐Berlekamp,Conway和Guy为你的数学游戏赢得方式。我认为,第3卷涉及这些类型的游戏。

答案 1 :(得分:3)

看起来像Minimax问题。

答案 2 :(得分:1)

我想这个任务有更快的解决方案。我会想。 但我可以给你一个O(N!* N ^ 2)复杂度的解决方案。

首先,请注意从N排列中选取数字等同于以下内容:

  1. 从N排列中选择号码。我们是X号。

  2. 使用规则重新分配号码:

  3. 1 = 1

    2 = 2

    ...

    X-1 = X-1

    X =没什么,它消失了。

    X + 1 = X

    ...

    N = N - 1

    你得到了N-1号码的排列。

    示例:

    1 5 6 4 2 3

    选择2

    1 5 6 4 3

    重新分配

    1 4 5 3 2

    让我们使用这个作为移动,而不仅仅是选择。很容易看到游戏是等价的,玩家A在这个游戏中赢得一些排列,当且仅当它赢得了原始。

    让我们给出N个数字,N-1个数字,...... 2个数字的所有排列代码。

    定义F(x) - > {0; 1}(其中x是置换代码)是当前

    时为1的函数

    玩家获胜,如果当前玩家失败则为0。容易看到F(1 2 .. K-1 K)= 0。

    F(x)= 1如果至少在移动时将x转换为y,并且F(y)= 0。

    F(x)= 0如果任何将x转换为y,F(y)= 1的移动。

    所以你可以使用带有记忆的递归来计算:

    Boolean F(X)
    {
        Let K be length of permutation with code X.
        if you already compute F for argument X return previously calculated result;
        if X == 1 2 .. K return 0;
        Boolean result = 0;
        for i = 1 to K do
        {
             Y code of permutation get from X by picking number on position i.
             if (F(y) == 0)
             {
                 result = 1;   
                 break;
             }
        }
        Store result as F(X);
        return result;
    }
    

    对于每个参数,我们只计算一次这个函数。有1个!长度为1,2的排列!长度为2的排列.N!长度为N的排列。对于置换长度K,我们需要进行O(K)运算来计算。所以复杂性将是O(1 * 1!+ 2 * 2!+ .. N * N!)=< = O(N!* N ^ 2)= O(N!* N ^ 2)

答案 3 :(得分:0)

这是Wisdom的Wind算法的Python代码。它打印出RobotA的胜利。

import itertools

def moves(p):
    if tuple(sorted(p)) == p:
        return
    for i in p:
        yield tuple(j - (j > i) for j in p if j != i)

winning = set()

for n in range(6):
    for p in itertools.permutations(range(n)):
        if not winning.issuperset(moves(p)):
            winning.add(p)

for p in sorted(winning, key=lambda q: (len(q), q)):
    print(p)