算法作业2-轮流取石头游戏

两个足够聪明的人玩轮流取石头的游戏,谁取到最后一个石头谁就赢了,他们一次只能取1个、3个、7个或8个石头,写一程序判断n个石头时先取的人是输还是赢。

输入格式:

一个整数n,其值不超过10000000。

输出格式:

如果先取的人赢,请以单独一行输出1,否则输出0。

输入样例:

这里是3组输入。

1

10

300

输出样例:

上面3组数据对应的输出分别如下:

1

1

0

首先举个例子,假如石头的总数为1,那么第一个取的人必然获胜。

然而到了总数为2的时候,第一个取的人只能拿一个,所以剩下的那一个就落在了第二个人手中,第二个人获胜。

石头总数为3,第一个人取石头可以选择取一个,剩下的两个中第二个人也只能拿一个,最后一个石头还是落在第一个人手中;或者第一个人可以直接选择拿取三个石头完结比赛。

石头总数为4,第一个人依然有两种选择,拿一个或者三个,但是这样无论第一个人第一次拿取几个石头,最后一个石头必然落在第二个人手中,即第二个人必胜。

石头总数为5,

第一个人第一次依然有两种选择,

第一种情况

如果第一个人第一次拿1个,剩下的4个石头第二个人有两种选择的机会,第二个人的第一次可以拿一个或者三个石头。如果第二个人拿一个,剩下的三个石头会被第一个人的第二次全部拿走,这样第一个人获胜;如果第二个人拿三个,剩下的一个也会被第一个人第二次拿走,获胜的依旧是第一个人。

第二种情况

如果第一个人第一次拿三个,剩下的两个石头第二个人只有一种选择就是拿一个,剩下的一个石头会被第一个人第二次拿走,第一个人获胜

所以石头总数为5的情况第一个拿的人必胜。

举例到了这里明眼人已经看出来些许端倪,我们是不是可以发现,当第一个人拿一个石头的时候剩下的4个石头交给了第二个人手中做选择,那么通过我们上面的例子在石头总数为4的时候是不是第二个取石头的人必赢?既然第二个取石头的人必赢(总数为4的时候),那么第一个人把剩下的4个石头交给第二个人,第二个人就成了第一个拿石头总数为4的人,而此时的第一个拿石头总数为5的人在石头总数为4面前成了第二个人,也就是说此时第一个取石头总数为5的人必胜。

同理依然是总数为5,如果我们的第一个人拿了三个石头,那么剩下的两个石头交给第二个人做选择,第二个人成了取石头总数为2的第一个人,而取总数为5的第一个人变成了取石头总数为2的第二个人。上面的例子中石头总数为2的人是不是第二个取的人必胜?所以,我们应该有大致的理解了。

说成大白话就是,第一个取石头的人总是想尽办法把自己必输的石头数留给第二个人,也就是说两个大聪明绞尽脑汁把自己必输的局面留给另一个人。

采用的思路就是从一个石头到n个石头去试,如果第i-1或者i-3或者i-7或者i-8中有一种情况或多种是第一个人输,那么第一个人就会拿取对应的1,3,7,8个石头,把自己必输的局面留给另一个人,让自己成为必输局面的第二个拿石头的人。(看不懂的话就是:石头总数为6的时候第一个拿的人必输,当石头总数为9的时候,9-3=6,所以第一个人第一次就会拿3个石头,把6个石头留给第二个人)

经过这一番解释,代码应该特别容易实现:

#include<bits/stdc++.h>
using namespace std;
long long int a[100000005];
int main(){
	long long int n;
	a[1]=1;
	a[2]=0;
	a[3]=1;
	a[4]=0;
	a[5]=1;
	a[6]=0;
	a[7]=1;
	a[8]=1;
	cin>>n;
	if(n<=8)cout<<a[n];
	else{
		for(int i=9;i<=n;i++){
			if(a[i-1]==0)a[i]=1;
			else if((a[i-3]==0)||(a[i-7]==0)||(a[i-8]==0))a[i]=1;
			else a[i]=0;
		}
		cout<<a[n];
	}
	return 0;
}

但是但是!

这个题肯定有内存的限制,题目上没说,如果是平常的64M的内存的话这样是可以过的,但是我记得这个题的内存要求是1M,所以这样做会超内存。不过我们可以利用这个代码实验大量的数据,找出其中的规律。

经过大量数据测试后得出规律:当n%15==0或2或4或6时都是第二个人赢,其余情况是第一个人赢了

这样的话就可以写出很简化的代码了:

AC代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
	int n;
	cin>>n;
	if(n%15==0)cout<<0;
	else if(n%15==2)cout<<0;
	else if(n%15==4)cout<<0;
	else if(n%15==6)cout<<0;
	else cout<<1;
}

看懂了点个赞支持下吧!

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值