巴什博奕

看到巴什博奕很好的一篇博客,链接在此大神的哟
巴什博奕基础1:
只有一堆n个物品,两个人轮流从这堆物品中取物,规定每次至少取一个,最多取m个。最后先取光者获胜。
当然每个人都想获胜,所以每个人都会采取对自己有优势的最优的方法。
显然,如果n=m+1,那么由于一次最少能取1个,最多能取m个,所以无论先取者拿走多少个,后取者都能够一次拿走剩余的物品,后者取胜。
即如果n = m + 1; 我们假设第一个人拿走了k个, 还剩下 m + 1 - k。 因为1<=(m + 1 - k)<= m, 所以, 剩下的部分一定可以被第二个人一次性取走。
将这一规律进行推广:(假设先取者为A,后取者为B)
如果n=(m+1)r+s,(r∈N,s<=m),意即n%(m+1)!=0,则A第一次先拿走s个物品,剩下的即为(m+1)的倍数r(m+1),那么还需要r轮能够全部取完,每一轮中,若B拿走k个,那么A可以相应策略地取走(m+1-k)个,这样最后一轮A可以保证全部取完,A获胜。否则,若n%(m+1)==0,则B获胜。

if(n%(m+1)!=0)
    printf("A\n");
else
    printf("B\n");

如果规定先取光着输,那么:
谁都不想输,由于每一轮至少取一个,那么每个人都想最好给对方留下只剩一个(如果不是一个,那么对方会再留给自己一些的),那么对方一下子取完,自己就能获胜。
如果n-1=m+1,如果A取k个,那么B肯定取m+1-k个,从而给A留下一个,B获胜。
将这一规律进行推广:
如果n-1=(m+1)*r,即(n-1)%(m+1)==0,那么会进行r轮,每一轮中A先取k个,B会相应取m+1-k个,最后B取完只剩下1个,A把全部取完,B获得胜利。

if((n-1)%(m+1)==0)
    printf("B\n");
else
    printf("A\n");

巴什博奕演变1:
Alice和Bob在玩这样的一个游戏, 给定k个数组a1,a2,a3,……ak。 一开始, 有x枚硬币, Alice和Bob轮流取硬币, 每次所取硬币的枚数硬顶要在 a1,a2,a3,……ak之中。 Alice先取, 取走最后一枚硬币的一方获胜。 当双方都采取最优策略的时候, 谁会获胜? 题目假定a1,a2,a3,……ak之中一定有1。

分析轮到自己时还有m枚硬币的胜负情况:
1、取光所有硬币的获胜,也就是说轮到自己时没有硬币了,那就输了。因此m=0时是必败态;
2、如果对于某个i,存在(1<=i<=k),(m-a[i])是必败态,那么j就是必胜态了(意即,当前有m枚硬币,自己取了a[i]枚之后剩下的m-a[i]枚导致对手必败,那么自己就是必胜的咯);
3、如果对于任意的i,m-a[i]都是必胜态的话,那么m就是必败态咯(意即,当前有m枚硬币,无论自己怎么取,剩下的硬币都会使对手胜利,那么自己就必败无疑啦);
按照规则,利用动态规划,令m从0开始从小到大计算必胜态,大数的状态由小数获得哦。只需最后看x的状态即可。
用bool win[]数组记录每一个数字记录的状态。
由规则2可知,
只要m-a[i]中的任意一个是必败态,那么m就可为必胜态,即
win[m]=(!win[m-a[1]])||(!win[m-a[2]])||…||(!win[m-a[k]]) //(数组a[]需要从小到大排列哦)(一真则真,全假为假)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int x,k;
bool win[100000];//表示轮到某一个人时剩下i个硬币,胜负情况 ,为真则该人必胜,为假则必败 
int a[100000];
void Bash()
{
    win[0]=false;
    for(int i=1;i<=x;i++)
    {
        win[i]=false;
        for(int j=0;j<k;j++)
            win[i]|=(a[j]<=i&&!win[i-a[j]]); 
    }//a[j]<=i表示还可以取a[j]个硬币,win[i-a[j]]为假表示一方取完(i-a[j])个硬币之后,对手方是必败的,那么win[i]为真则表示此方必胜 
}
int main()
{
    while(~scanf("%d%d",&x,&k))
    {
        for(int i=0;i<k;i++)
            scanf("%d",&a[i]);
        sort(a,a+k);
        memset(win,false,sizeof(win));
        Bash();
        if(win[x])
            printf("A\n");
        else
            printf("B\n");
    }
    return 0;
}

若规定先取完的输了,
那么思路是一样的,如果自己取过之后对方存在必败态,那么自己是必胜态,否则自己是必败态,都需要从小到大一个个取判断,区别是,上面的win[0]是false,是输的状态,此时的win[0]是true,是赢的状态。
代码如下:

#include<iostream> 
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#define ll long long
using namespace std;
int a[3]={1,3,4};
bool win[1000000];
int main()
{
    int i,j,n;
    int flag=0;
    //win[0]=true;先取完的输了 
    win[0]=false;//先取完的赢了 
    while(~scanf("%d",&n))
    {
        for(i=1;i<=n;i++)
        {
            for(j=0;j<3;j++)
            {
                if(a[j]<=i&&(!win[i-a[j]]))
                {
                    flag=1;
                    win[i]=true;
                    break;
                }
            }
        }
        if(win[n])
            printf("A\n");
        else
            printf("B\n");
    }

}

题目链接:Click here
1067 Bash游戏 V2
基准时间限制:1 秒 空间限制:131072 KB 分值: 10 难度:2级算法题 收藏 关注
有一堆石子共有N个。A B两个人轮流拿,A先拿。每次只能拿1,3,4颗,拿到最后1颗石子的人获胜。假设A B都非常聪明,拿石子的过程中不会出现失误。给出N,问最后谁能赢得比赛。
例如N = 2。A只能拿1颗,所以B可以拿到最后1颗石子。
Input
第1行:一个数T,表示后面用作输入测试的数的数量。(1 <= T <= 10000)
第2 - T + 1行:每行1个数N。(1 <= N <= 10^9)
Output
共T行,如果A获胜输出A,如果B获胜输出B。
Input示例
3
2
3
4
Output示例
B
A
A

分析:
由上述规则可知
win[m]=(!win[m-1])||(!win[m-3])||(!win[m-4]);
先打表找规律可得:

#include<iostream>//打表哦, 
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#define ll long long
using namespace std;
//win[i]=(!win[i-1])||(!win[i-2])||(!win[i-3]) 一真则真,全假为假 
int win[100];
int main()
{
    memset(win,0,sizeof(0));
    win[1]=win[3]=win[4]=1;
    for(int i=5;i<=20;i++)
        if(!win[i-1]||!win[i-3]||!win[i-4])
            win[i]=1;
    for(int i=0;i<=20;i++)
        cout<<i<<' '<<win[i]<<endl;
}//7个一循环呢 

结果为{0,1,0,1, 1,1,1}循环
即win[m]=win[m%7];为0则必败,1则必胜。
即,为0则先取的A败,B胜;1则A胜。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int win[7]={0,1,0,1,1,1,1,};
int n;
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        printf(win[n%7]?"A\n":"B\n");
    } 
    return 0;
}

巴什博奕演变2:
n枚硬币排成一个圈。Alice和Bob轮流从中取一枚或者两枚硬币, 不过, 取两枚时这两枚必须是连续的。硬币取走之后留下空位,想个空位的硬币被认为是不连续。 A开始先取, 取走最后一枚硬币的一方获胜。双方都采取最优策略的时候谁会取胜?

这个上面大神博客思路清晰,简单来说,就是后者根据前者所取硬币的个数做出相应的对策,从而使得剩下的硬币呈对称状态,也就是说两段留出相同数量。所以当总个数n<=2时,先手赢,
n>=2时,后手赢。
代码:

if(n<=2)
    printf("A\n");
else
    printf("B\n");
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值