题目
牛牛和羊羊都很喜欢青草。今天他们决定玩青草游戏。最初有一个装有n份青草的箱子,牛牛和羊羊依次进行,牛牛先开始。在每个回合中,每个玩家必须吃一些箱子中的青草,所吃的青草份数必须是4的x次幂,比如1,4,16,64等等。不能在箱子中吃到有效份数青草的玩家落败。假定牛牛和羊羊都是按照最佳方法进行游戏,请输出胜利者的名字。
输入描述:
输入包括t+1行。 第一行包括一个整数t(1 ≤ t ≤ 100),表示情况数. 接下来t行每行一个n(1 ≤ n ≤ 10^9),表示青草份数
输出描述:
对于每一个n,如果牛牛胜利输出"niu", 如果羊羊胜利输出"yang"。
示例1
输入
3 1 2 3
输出
niu yang niu
思路分析:
- 这个题目,输入int,输出boolean,很容易想到找规律。
可是应该怎么找规律呢,我们可以先用暴力解法,然后直观地看结果是否满足某种规律
- 暴力解法:运用递归的解决决策树,先算出前几个作为递归结束的条件。
1,3,4时牛赢,0,2,5时羊赢
- 然后,牛选一个数(迭代:4的次幂),再把决策交给羊(羊来调用函数)
如果,羊的递归调用中只要有一次是输,说明牛可以赢
- 同理,来到羊决策时,选一个数,把决策权交给牛。。。。
- 查看输出结果
- 找到规律:后先后先先,五个一轮回
怎么保证,这个规律在大于50仍然适用呢?
我么只设置了前5个的值,这样算出来,在大于16甚至大于32都是满足这个规律。
那么大胆推测,在大于64时也会满足这样的规律
易错点
- 在暴力解法中要注意到base会不会溢出,因为n已经接近2^9,如果再乘以4,有可能会超出int的范围。
难点:
- 不要去钻牛角尖,认为这种解法是旁门左道
代码展示
暴力解法:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main{
public static String winner(int num){
if(num<5){
return (num==0||num==2)?"后手":"先手";
}
int base = 1;
while(base<num){
if(winner(num-base).equals("后手")){//所有博弈情况中,能否找到一种胜出的解。如果能,就用这个解
return "先手";
}
if(base*4>num){//防止溢出
break;
}
base = base*4;
}
return "后手";
}
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());//10^9用int就足够
for(int i = 0;i<50;i++){
System.out.println(i+"份青草时: "+ winner(i));
}
}
}
正儿八经解法:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main{
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());//10**9用int就足够
int grass[] = new int[n];
for(int i=0;i<n;i++){
String str = br.readLine();
grass[i] = Integer.parseInt(str);
}
for(int i=0;i<n;i++){
grass[i] = grass[i]%5;
System.out.println((grass[i]==0||grass[i]==2)?"yang":"niu");
}
}
}