花生米(四)
描述
五一长假第四天,Tom逛了N个bbs,做了N^2个脑筋急转弯题,终于发现了每次吃完花生米嘴里都是苦味的原因:自己总会吃到最后一粒花生米。
五一长假第五天,Tom和Jerry在仓库散步的时候发现了n堆花生米(这是什么仓库啊?!)。这次Tom制定分花生米规则如下:
1、首先选出最苦的一粒花生米,放到一个瓶子里;
2、Tom和Jerry轮流从任意一堆花生米中取出任意粒吃掉;
3、如果Tom吃到最后一粒花生米(瓶子里的花生米除外),Jerry必须吃掉瓶子里的花生米;如果Jerry吃到最后一粒花生米(瓶子里的花生米除外),Tom自愿吃掉瓶子里的花生米;
4、为显示规则的公平性,Jerry可以选择先取或者后取。
Jerry当然希望瓶子里的花生米被Tom吃掉。请计算,Jerry为了达到目的应该先取还是后取。
输入
本题有多个测例。
每个测例的输入第一行是一个整数n,n大于零小于等于10,代表花生米的堆数(取出最苦花生米后);接下来n行每行一个不超过100的正整数,分别代表一堆花生米的粒数(取出最苦花生米后)。
n等于0表示输入结束,不需要处理。
输出
每个测例在单独的一行内输出一个整数:Jerry先取输出1;Tom先取输出0。
输入样例
2
1
1
2
1
100
0
输出样例
0
1
思路
的区别在于前两个都是Jerry希望Tom拿到最后一颗花生米。现在这个题是Jerry希望自己拿到最后一颗花生米。并且 Tom和Jerry轮流从任意一堆花生米中取出任意粒吃掉。这个初看觉得比较复杂,所以我自己把情况分成了几种情况进行讨论:
1.只有1堆花生米,那Jerry必须先手,否则让Tom先手的话,Tom直接全部取走,先手必胜。所以Jerry要先取,答案输出1.(测试数据没有这个测试点)。
2.所有的花生堆都是1个为一堆,设有n堆,如果n是偶数,那么后手必胜,Jerry选择后手,答案输出0;如果n是奇数,那么先手必胜,Jerry选择先手,答案输出1。
3.如果存在花生数量>1的花生堆:
(1)如果总共就两堆花生:如果两堆数目一样,后手只要按照先手的取法跟着取就好了。后手必胜,输出0;否则先手必胜,输出1;
(2)如果花生堆数>2:这时候需要判断含1个花生米的堆数,和含>1个花生米的堆数。sign1=0表示只含一个花生米的堆数为偶数,sign2=0表示含>1个花生米的堆数为偶数。(这里偶数不含0,为0就表示不存在这种类型的花生堆,应该认为这时的sign=1)
当sign1 == 1 &&sign2 == 1的时候: 全奇数堆先手必胜,所以Jerry必须先手:比如1 1 1 3 3 3–>1 3 3 3先手必胜 (后手无法赢)
当存在偶数堆,则让对手取成全奇,在此之前,Jerry保持非全奇 :比如1 1 1 1 3 3 3 3 .如果先手选3,后手跟着选3,直到3用完,先手选择1,后手到达必胜态 。 如果 先手选3中的2,–>1 1 1 1 1 3 3 3 后手选 1–>1 1 1 1 3 3 3,直到3用完,先手选择1,后手到达必胜态。 同理1 1 1 3 3 3 3类型和1 1 1 1 3 3 3类型。
ps: 注意 7 3 3 3 3 3 3 3 这种类型即含1个花生米的堆数=0,这个时候sign1=1,sign2=1,就是指只存在奇数堆,先手必胜。
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1000+50;
int n,a[maxn];
int main(){
while(1){
cin>>n;
if(n==0)break;
int sum=0,cnt=0,tot=0;
for(int i=1;i<=n;i++){
cin>>a[i],sum+=a[i];
if(a[i]==1)cnt++;
}
if(n==1){
cout<<1<<endl;
}
else if(cnt==n){
if(n%2==0)cout<<0<<endl;
else cout<<1<<endl;
}
else{
if(n==2){
if(a[1]==a[2])cout<<0<<endl;//对称取
else cout<<1<<endl;//Tom先手先让a[1]==a[2],Tom对称取,Jerry必败,所以Jerry必须先手
}
else{
int sign1=0,sign2=0;
if(cnt>0&&cnt%2==0)sign1=0;//只含1个花生米的堆数为偶数
else sign1=1;
if((n-cnt)%2==0)sign2=0;//含>1个花生米的堆数为偶数
else sign2=1;
if(sign1&&sign2)cout<<1<<endl;//全奇数堆先手必胜,所以Jerry必须先手:比如1 1 1 3 3 3-->1 3 3 3先手必胜 (后手无法赢)
else cout<<0<<endl;//如果存在偶数堆,则让对手取成全奇,在此之前,Jerry保持非全奇
//如果1 1 1 1 3 3 3 3 .如果先手选3,后手跟着选3,直到3用完,先手选择1,后手到达必胜态
//如果 先手选3中的2,-->1 1 1 1 1 3 3 3 后手选 1-->1 1 1 1 3 3 3,直到3用完,先手选择1,后手到达必胜态。
//同理1 1 1 3 3 3 3类型和1 1 1 1 3 3 3类型。
//注意 7 3 3 3 3 3 3 3 这种类型即cnt==0,这个时候sign1=1,sign=1,就是指只存在奇数堆,先手必胜。
}
}
}
return 0;
}
/*7
3 3 3 3 3 3 3
*/
//Jerry 后手必胜的条件:后手且吃掉最后的花生米,则Jerry无法后手胜利。