此DP问题左移的目的是什么?

时间:2019-07-30 21:42:03

标签: c

我最近在网上找到了此问题的解决方案(来自leetcode.com的原始信息):

在“ 100个游戏”中,两个玩家轮流将1..10中的任何整数添加到连续总计中。首先使跑步总数达到或超过100的玩家。 如果我们改变游戏规则以使玩家不能重复使用整数怎么办? 例如,两个玩家可能轮流从1..15的公共号码池中抽奖,而没有替换,直到总数达到> = 100。

给定一个整数maxChoosableInteger和另一个整数desiredTotal,假设两个玩家都发挥最佳状态,那么确定第一个移动的玩家是否可以强制胜利。 您始终可以假设maxChoosableInteger不大于20,desiredTotal不大于300。

int canWin(int *dp, int v, int m, int total) {
    int i, hewins;

    if (dp[v] != -1) return dp[v];      // already resolved

    for (i = m; i >= 1; i --) {
        if (v & (1 << (i - 1))) continue;
        v |= (1 << (i - 1));
        if (i >= total) {
            dp[v] = 1;          // resolve to win
            return 1;
        }
        hewins = canWin(dp, v, m, total - i);
        if (!hewins) return 1;
        v &= ~(1 << (i - 1));   // not able to resolve, try with different number
    }
    dp[v] = 0;      // resolve to loose
    return 0;
}
bool canIWin(int maxChoosableInteger, int desiredTotal) {
    int w, dp[1 << 20];

    // none can win
    if (maxChoosableInteger * (maxChoosableInteger + 1) / 2 < desiredTotal) return false;

    //dp = calloc((1 << (maxChoosableInteger)), sizeof(int));
    //assert(dp);
    memset(dp, -1, (1 << (maxChoosableInteger)) * sizeof(int));

    w = canWin(dp, 0, maxChoosableInteger, desiredTotal);

    //free(dp);

    return w;
}

在上面的代码中,在3个主要实例中使用了左移。

    memset(dp, -1, (1 << (maxChoosableInteger)) * sizeof(int));

dp[1 << 20]

以及类似以下内容的所有实例:

        if (v & (1 << (i - 1))) continue;

该问题的解决方案是递归的,并且这个问题可以递归地解决,但是首先我不确定为什么您需要这么大的数组来存储所有递归调用。每个输入最多应有20个递归调用(因为canIWin(maxinteger, total) = canIWin(maxInteger - 1), total) OR canIWin((maxInteger - 2), total) OR ... canIWin(1, total)(实际上不能转到1因为逻辑上的原因,但这只是使想法得以传播)

对于为什么使用这种左移的任何解释将不胜感激。

0 个答案:

没有答案