最简单的巴什博弈

巴什博弈

所谓巴什博弈,是ACM题中最简单的组合游戏,大致上是这样的:

只有一堆n个物品,两个人轮流从这堆物品中取物,规定每次至少取1个,最多取m个,最后取光者得胜。
 
分析: 
   显然,如果n = m + 1,那么由于一次最多只能取m个,所以,无论先取者拿走多少个,后取者都能够一次拿走剩余的物品,后者取胜。因此我们发现了如何取胜的法则:
如果 n = (m + 1) * r + s ,(r为任意自然数,s≤m),即n%(m+1) != 0,则先取者肯定获胜。
   每一局,你都必须构建一个局势,这个局势就是每次都留给对手m+1的倍数个物品。因为,如果n=(m+1)r + s,(r为任意自然数,s≤m),那么先取者要拿走s个物品,如果后取者拿走k(≤m)个,那么先取者再拿走m+1-k个,结果剩下(m+1)(r-1)个,以后保持这样的取法,那么先取者肯定获胜。总之,要保持给对手留下(m+1)的倍数,就能最后获胜。
//下面就来看一下这类题 
 

 好运!该死的英语四级!

 Problem Description
大学英语四级考试就要来临了, Kiki和Cici 在紧张的复习之余喜欢打牌放松。“升级”?“斗地主”?那多俗啊!作为计算机学院的学生,Kiki和Cici打牌的时候可没忘记专业,她们打牌的规则是这样的:
1、 总共n张牌;
2、 双方轮流抓牌;
3、 每人每次抓牌的个数只能是2的幂次(即:1,2,4,8,16…)
4、 抓完牌,胜负结果也出来了:最后抓完牌的人为胜者;
假设Kiki和Cici都是足够聪明并且每次都是Kiki先抓牌,请问谁能赢呢?

 Input
输入数据包含多个测试用例,每个测试用例占一行,包含一个整数n(1<=n<=1000)。

Output
若Kiki能赢的话输出“Kiki”,否则输出“Cici”,每个实例的输出占一行。

Sample Input
1
3

Sample Output
Kiki
Cici

 分析:
 
如果你是先手,考虑你的必胜态。注意,因为任何正整数都能写成若干个2的整数次方幂之和(相当于十进制转二进制)。由于规定只能取2的某个整数次方幂,只要你留给对手的牌数为3的倍数时,那么你就必赢,因为留下3的倍数时,对手有两种情况:
1:如果轮到对方抓牌时只剩3张牌,对方要么取1张,要么取2张,剩下的你全取走,必赢!
2:如果轮到对方抓牌时还剩3*k张牌,对手不管取多少,剩下的牌数是3*x+1或者3*x+2。轮到你时,你又可以构造一个3的倍数。 所以无论哪种情况,当你留给对手为3*k的时候,你是必胜的。
题目说Kiki先抓牌,那么当牌数为3的倍数时,Kiki就输了。否则Kiki就能利用先手优势将留给对方的牌数变成3的倍数,就必胜。
 
代码如下:
#include <iostream>
using namespace std;
int main ()
{
    int num;
    while (cin>>num )
    {  
        if(num%3!=0)
            cout<<"Kiki"<<endl;
        else cout<<"Cici"<<endl; 
    }
    return 0; 
}

  土地拍卖

 

Problem Description
小鸡同学和鹏程同学始终没有逃过退学的命运,因为他们没有在程序设计竞赛中获奖,还为了争抢莎莎大打出手。现在等待他们的只能回家种田。要种田得有田才行,小鸡听说街上正在举行一场拍卖会,拍卖的物品正好就是一块田地。于是,小鸡带上他的全部积蓄,冲往拍卖会。后来发现,整个拍卖会只有小鸡和他的死对头鹏程。通过打听,小鸡知道这场拍卖的规则是这样的:刚开始底价为0,两个人轮流开始加价,不过每次加价的幅度要在1~N之间,当价格大于或等于田地的成本价M时,就把这块田地卖给这次叫价的人。小鸡和鹏程虽然比赛不行,但是对拍卖却十分精通,而且他们两个人都十分想得到这块田地。所以他们每次都是选对自己最有利的方式进行加价。由于抽签决定,所以每次都是由小鸡先开始加价,请问,第一次加价的时候,小鸡要出多少才能保证自己买得到这块地呢?
 
Input
本题目包含多组测试,请处理到文件结束(EOF)。每组测试占一行。每组测试包含两个整数M和N(含义见题目描述,0<N,M<1100)
 
Output
对于每组数据,在一行里按递增的顺序输出小鸡第一次可以加的价。两个数据之间用空格隔开。如果小鸡在第一次无论如何出价都无法买到这块土地,就输出"none"。
 
Sample Input
4 2
3 2
3 5
 
Sample Output
1
None
3 4 5
 
 分析:
这道题就是一般的巴什博弈,如果m%(n+1)=0,就是必败态;如果m<=n,就可能出现多种选择;如果是一般情况就只有上述所说的一种选择
 
代码如下: 
# include<stdio.h>
int main()
{
    int n,m;
    while(scanf("%d %d",&m,&n)!=EOF)
    {
        if(m%(n+1)==0)
        {
            printf("none\n");
            continue;
        } 
        if(m<=n)
        {
            printf("%d",m);
            for(int i=m+1; i<=n; i++) 
                printf(" %d",i);
            printf("\n");
            continue;
        } 
        printf("%d\n",m%(n+1));
    } 
    return 0;
}

 

 

 

 

 

posted on 2012-10-27 13:02  即为将军  阅读(1041)  评论(0)    收藏  举报

导航