力扣Nim游戏c语言,力扣292.Nim游戏---动态规划与巧妙的数学思想

292. Nim 游戏

你和你的朋友,两我的一块儿玩 Nim 游戏:web

桌子上有一堆石头。

大家轮流进行本身的回合,你做为先手。

每一回合,轮到的人拿掉 1 - 3 块石头。

拿掉最后一块石头的人就是获胜者。

假设大家每一步都是最优解。请编写一个函数,来判断你是否能够在给定石头数量为 n 的状况下赢得游戏。若是能够赢,返回 true;不然,返回 false 。svg

示例 1:函数

输入:n = 4

输出:false

解释:若是堆中有 4 块石头,那么你永远不会赢得比赛;

由于不管你拿走 1 块、2 块 仍是 3 块石头,最后一块石头老是会被你的朋友拿走。

示例 2:spa

输入:n = 1

输出:true

示例 3:code

输入:n = 2

输出:truexml

提示:token

1 <= n <= 231 - 1

开始没有想太多,一看就想到动态规划问题

即对于先手来讲,即若是在他的回合只剩下0个石头时他是必败的,若是剩下1~3个石头他是必胜的。

因此当有n个石头时,若是先手对应n个石头,后手则对应n-1或n-2或n-3个石头,则要求先手对应n个石头能不能必赢时,咱们须要知足后手的n-1,n-2,n-3三个方案中有一个必输的方案便可。由于对手是十分聪明的,若是不能在三个中找到使得后手必输的方案,咱们就必定会输。而因为咱们也是十分聪明的,因此咱们也只须要在三个方案中找到一个使得后手必输的就好了,由于后手的三个方案究竟是哪个都是由咱们先手的决定的。游戏

因此不妨设a[n]为表示n个石头时,先手的输赢状况。

因此可列出a[n]=!(a[n-1]==1&&a[n-2]==1&&a[n-3]==1)数学

由于此时已经为n个石头了,因此式子后面的a[n-1]==1&&a[n-2]==1&&a[n-3]==1则为下一个状态了,即由于后手在先手先操做,操做后,他本身也就变成了先手,因此此时能够用来表示后手的输赢状况了。

也能够这样理解:

在n个石头变成n-1或n-2或n-3时已经表明先手拿过了,则此时后手就至关于为n-1或n-2或n-3个石头的先手了。it

可是这样会超时:

bool canWinNim(int n){

bool a[n];

if(n==1||n==2||n==3)

return 1;

a[0]=1;

a[1]=1;

a[2]=1;

for(int i=3;i

{

if(a[i-1]==1&&a[i-2]==1&&a[i-3]==1)

a[i]=0;

else

a[i]=1;

}

return a[n-1];

}

查看题解后发现可直接数学化思考:

即当1,2,3个石头时先手都必赢,4个则必输。当有5 个石头时,咱们发现若开始先手拿1个,则后手也必输,因此能够知道即当谁的回合对应4个石头时谁就必输,由于你们都是聪明人,不论他这回合拿多少,下一我的老是能拿完剩下的全部石头。

而当咱们知道这个“逢四必输”后,咱们能够再看看8个石头,咱们发现当先手拿1~3个石头后,后手老是有一种方案来使得最后给咱们的仍是4个石头,因此咱们仍是必输,因此咱们知道了“逢八必输”,当12个石头时同理咱们先手也会碰到8个石头的状况…因此咱们可知一旦石头为4的倍数咱们老是会因为后手的“聪明操做”而致使面临4的倍数的石头的状况,因此可知代码:

bool canWinNim(int n){

return n%4!=0;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值