当前位置:编程学习 > C/C++ >>

编程之美1.13——NIM(3)两堆石头的游戏

问题:
       假设有两堆石头,有两个玩家会根据如下的规则轮流取石头:
每人每次可以从两堆石头中各取出数量相等的石头,或者仅从一堆石头中取出
任意数量的石头;最后把剩下的石头一次拿光的人获胜。请问在哪些局面(依
据两堆石头中的石头个数)下,先取石头的玩家有必胜的策略。


解法:
      类似构造质数的筛选方法,这里我们利用找到的必输局面(后取的玩家有必胜策略)
来筛去掉能通过一次操作达该必输局面的其它必胜局面(先取的玩家有必胜策略)。
最后选出的局面都是必输局面。
构造必胜策略:
      如果一开始的局面就是必输局面,那么可能先取的玩家没有必胜策略(当然如果后取
的玩家不太聪明,先取的玩家依然有可能能赢)。如果一开始的局面不是必输局面,
那么先取的玩家一定有必胜策略,且必胜策略就是保证每次都将当前非必输局面转变
为必输局面(后取的玩家必输)。


[cpp]
#include <iostream> 
#include <algorithm> 
#include <cstdlib> 
using namespace std; 
 
// filter method 
#define MAXN 10000 
#define CLEAR(a)  memset((a), 0, sizeof(a)) 
 
char ns[MAXN][MAXN];  // 用于筛选出必输局面 
int v[MAXN];<span style="WHITE-SPACE: pre">   </span>// 保存(ind,v[ind])的必输局面对 
 
int main() 

    int a, b, i, j, abmin, abmax, k; 
<span style="WHITE-SPACE: pre">   </span>// 输入的数据(a,b)表示两堆石头中石头的个数对 
    while (cin >> a >> b) 
    { 
<span style="WHITE-SPACE: pre">       </span>// 筛选出可能用到的所有必输局面 
        abmax = max(a, b); 
        for (i=1; i<=abmax; i++) 
        { 
            if (v[i]) continue; 
            for (j=i+1; j<=MAXN; j++) 
            { 
                if (!ns[i][j]) 
                { 
                    printf("(%d,%d) ", i, j); 
                    v[i] = j; 
                    v[j] = i; 
                    for (k=1; k+i<=abmax; k++) 
                        ns[i+k][j+k] = 1; 
                    break; 
                } 
            } 
        } 
        cout << endl; 
<span style="WHITE-SPACE: pre">       </span>// 使用必胜策略 
        do 
        { 
            printf("current (%d,%d)\n", a, b); 
<span style="WHITE-SPACE: pre">           </span>// 我方(先取的玩家)的策略 
            if (b==0) 
            { 
                printf("I: extract (%d,0) from (%d,0)\n", a, a); 
                a = 0; 
                break; 
            } 
            else if (a==0) 
            { 
                printf("I: extract (0,%d) from (0,%d)\n", b, b); 
                b = 0; 
                break; 
            } 
            else if (a==b) 
            { 
                printf("I: extract (%d,%d) from (%d,%d)\n", a, b, a, b); 
                a = b = 0; 
                break; 
            } 
<span style="WHITE-SPACE: pre">           </span>// 将非必输局面(a,b)转变为必输局面(v[b],b)或(a,v[a]) 
            else if (v[b] < a) 
            { 
                printf("I: extract (%d,0) from (%d,%d)\n",  
                    a-v[b], a, b); 
                a = v[b]; 
            } 
            else 
            { 
                printf("I: extract (0,%d) from (%d,%d)\n",  
                    b-v[a], a, b); 
                b = v[a]; 
            } 
<span style="WHITE-SPACE: pre">           </span>// 对方随机选取 
      &n

补充:软件开发 , C++ ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,