动态规划之——博弈问题

套路又有一些不太一样的解法(抓住必胜态和必败态的转化)

先看第一道题:

动态规划之——博弈问题_第1张图片
典型的博弈问题,算法也比较通俗易懂,采用动态规划的思想,即如果存在一种方式让对手变为必败态,那么你就处于必胜态;否则,你就处于必败态,对于这道题,稍加分析可以得出回合数不太多,于是我们可以采用递归的写法:

int judge(int larger,int smaller){
    if(larger < smaller){
        larger ^= smaller ^= larger ^= smaller;//保证第一个参数为较大数
    }
    if(smaller == 0){
        return 0;
    }
    else{
        int i = larger / smaller;
        for(;i > 0;i--){//若存在一种方案可以使得对手变为必败态,那么就处于必胜态
            if(judge(larger - smaller * i,smaller) == 0)
                return 1;
        }
        return 0;//否则就处于必败态
    }
}

第二道题

动态规划之——博弈问题_第2张图片
对于这道题如果还是用上面那道题的写法,那么必定是会TLE的,可以想象,复杂度应该是指数级别的,于是,就要采用动态规划的写法了,思路还是之前说过的,不变:

for(int i = 1;i <= n;i++){
            for(int j = 0;j < k;j++){
                if(i - methods[j] >= 0 && !dp[i - methods[j]]){//对于i,如果在给出的去石头方案中存在一种方案将i转化为后手必胜状态(包括0),则i为先手必胜状态
                    dp[i] = 1;
                    break;
                }
            }
        }

第三道题

动态规划之——博弈问题_第3张图片
这道题又和之前的两道不太一样,这道题的每回合的操作方案数是不固定的,如果还想像第二题那样操作,那么对于每个i,就又要再算一次可能的操作方案并且存下来,有些麻烦,在这里,给出一种想到了就惊呼,没想到就头破的方法:数学归纳法:假设3k为先手必败态,当k = 1时显然成立,现在讨论3(k + 1)即3k + 3的情况:先手的人可以取1,那么就剩3k + 2,那么后手的人就可以取2,使得先手的人处于先手必败态;先手的人可以取2,那么就剩3k + 1,那么后手的人就可以取1,使得先手的人处于先手必败态;先手的人再取4、8等情况,与之前的分类一致,由此可以得出,3k为必败态!,所以这道题的代码十分简短:

int judge(int n){
    if(n % 3 == 0)
        return 0;
    else
        return 1;
}

总结

以上就是我做到的OJ平台上的三道博弈题,有共性又有个性,十分有趣,难度适中,建议一做。

你可能感兴趣的:(动态规划)