简单博弈论

来源:互联网 发布:农村人的劣根性知乎 编辑:程序博客网 时间:2024/06/05 03:42

简单博弈论

1.HDOJ 2147

        这道题目的意思就是说给你一个n*m的格子,每次只能从右上角出发,只能往下,往左,往左下角走,每次只能走一步,谁不能走了,谁就输。其实就是谁先到达左下角,谁就赢了,输出先手KIKI的输赢情况。

         这道题的AC代码特别简单,将n和m乘起来,判断奇偶,然后输出即可,第一次做的时候,没反应过来就过了,现在补充一下详细的解释,博弈论分析问题常用N,P两种状态分析,

        P表示必败点,谁处于此位置,则在双方操作正确的情况下必败。

        N表示必胜点,处于此情况下,双方操作均正确的情况下必胜。

       现在我们一步一步的分析

       假设1 * 1,很明显这是必败点(定义为从这里出发),因为根本无路可走

       假设2 * 1,这是必胜点,当你从这里出发的时候,对手位于1 * 1这个必败点,相对的你就赢了

       假设2 * 2,这是必胜点,理由同上

       一步一步这样分析,就可以画出这样的图

       由此可以看出,实际上当n * m为奇数是必败点,所以代码如下:

    int n, m;    while(cin >> n >> m)    {        if(!n && !m)            break;        if((n * m) & 1)            cout << "What a pity!" << endl;        else            cout << "Wonderful!" << endl;    }

2.POJ 2234

        这道题目也是基本的取石子游戏,意思是现在有M堆石子,每次可以从任意一堆里面取走任意多的石子(当然不能不取或者超过这堆石子的最大指),谁不能取了谁就输,判断先手的输赢情况,当然保证两名选手都足够聪明(要不不保证,取石子游戏就没有意思了。。。。)。

       这道题当然可以使用SG定理直接求解,而且还特别简单,因为每堆石子的SG值就是它自身,即SG(x) = x,因为这堆石子,你取走以后剩下0, 1, 2 ... x - 2, x - 1.所以SG(x) = mex(SG[0], SG[1], SG[2], .....SG[x-2], SG[x-1]) = x;

       所以这道题都不需要打表了,直接异或累起来,判断是否非零即可,代码如下:

int main(){#ifdef LOCAL    ///freopen("in.txt", "r", stdin);    ///freopen("out.txt", "w", stdout);#endif // LOCAL    int n;    while(cin >> n)    {        int a, ans = 0;        for(int i = 0; i < n; ++i)        {            cin >> a;            ans ^= a;        }        if(!ans)            cout << "No" << endl;        else            cout << "Yes" << endl;    }    return 0;}

3.HDOJ 1846

        记得小时候玩的一个游戏,两个人轮流报数,每次只能报一个或者两个,谁先报道30谁就赢,不就是和这个题目一模一样的,想起来那时候学会这个规则,战无不胜啊,哈哈,这个就是巴什博奕,有一句话就是“加一整除,先手必输”,比如上面说的30个数字,也就是题干的30个石头,每次取不能超过2个,只要对手先取石子,我只需要保证我取得数字恰好能整除即可,比如他拿1 2,我就拿3;他拿4,我就拿5 6。这样下去,我永远抓住这个倍数,那么最后肯定是我赢。

        代码如下:

int main(){#ifdef LOCAL    ///freopen("in.txt", "r", stdin);    ///freopen("out.txt", "w", stdout);#endif // LOCAL    int t;    int n, m;    cin >> t;    while(t--)    {        cin >> n >> m;        if(n % (m + 1))            cout << "first" << endl;        else            cout << "second" << endl;    }    return 0;}



1 0