爱奇艺2017校招-Java开发-在线算法笔试题-NIM博弈问题,牛牛羊羊吃草
2017-10-14 22:32
561 查看
题目为:
牛牛和羊羊吃草,有t捆,每捆n个,两个人玩一个游戏,规则为,每个人每次只能吃4的幂,即1个,4个,或者16个。。。,直到无草可吃为输,每个人均会按照最佳策略进行。
输入t为堆数,之后输入每堆的个数;
如果牛牛赢,输出niu
如果羊羊赢,输出yang
5
1
2
3
4
5
niu
yang
niu
niu
yang
典型的NIM问题,博弈问题,对应每个石子数n可以分为两种状态:
N:先手赢
P:后手赢
(n)代表此刻的石子数量,因为每次可以拿1,4,16,...对应的子状况为(n-1),(n-4),(n-16)
(0)时,自己没有石子可拿,一定对手赢,状态为P
(1)时,自己全拿走一定赢,先手赢,状态N
(2)时,自己拿一个,对手拿走一个,自己肯定输,(2)对应子状态(1)为N,所以(2)为P
(3)时,对应子状态为(2)状态为P,所以(3)为N
(4)时,对应子状态为(0)-》P,(3)-》N,考虑到每个人会选择最佳策略,为了赢选择P(0),此时变为N
(5)时,可以选择拿1个,对应(4)为N 拿4个,对应(1)为N,都是先手赢,所以(5)为P,是后手赢
(6)时,可以选择拿1个,对应(5)为P, 拿4个,对应(2)为P,都是后手赢,所以(6)为N,是先手赢
….
以此类推,(17)时,子状态(1) (13) (16)..
N先手赢为1,P后手赢为0,当前石子为n时状态为NIM(n),则状态转移方程为
NIM(n-1) NIM(n-4) NIM(n-16) NIM()… NIM(n)
1 1 1 1 0
0 0 0 0 1
0 0 0 1 1
0 0 1 1 1
核心是
只要子状态包含P后手赢,那么为了赢,一定会选择这个状态为P的子状态,让自己赢
如果子状态都是N先手赢,那么无论怎么做,轮到下一个都必赢,自己一定会输。
import java.util.Scanner;
/**
* Created by Luna on 2017/10/14.
*/
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int loop = input.nextInt();
int c=0;
int[] num = new int[loop];
while (c<loop){
num[c]=input.nextInt();
c++;
}
for (int i = 0; i < loop; i++) {
System.out.println(NIM(num[i])?"niu":"yang");
}
}
public static boolean NIM(int k) {
if (k==0)
return false;
if (k==1)
return true;
int tmp=1;
int count=-1;
while(tmp<=k){ //判断输入值包含4的k次幂,对应有k+1个子状况
if(tmp==k)
return true;
tmp<<=2;
count++;
}
for (int i = 0; i <=count ; i++) {
int next=k - (int)Math.pow(4, i);
if(!NIM(next)) return true; //只要包含false 那么就选择它,让自己赢
}
return false;//如果子状况都是先手赢,那么自己必输。
}
}
运行结果:
5
1
2
3
4
5
niu
yang
niu
niu
yang
牛牛和羊羊吃草,有t捆,每捆n个,两个人玩一个游戏,规则为,每个人每次只能吃4的幂,即1个,4个,或者16个。。。,直到无草可吃为输,每个人均会按照最佳策略进行。
输入t为堆数,之后输入每堆的个数;
如果牛牛赢,输出niu
如果羊羊赢,输出yang
5
1
2
3
4
5
niu
yang
niu
niu
yang
典型的NIM问题,博弈问题,对应每个石子数n可以分为两种状态:
N:先手赢
P:后手赢
(n)代表此刻的石子数量,因为每次可以拿1,4,16,...对应的子状况为(n-1),(n-4),(n-16)
(0)时,自己没有石子可拿,一定对手赢,状态为P
(1)时,自己全拿走一定赢,先手赢,状态N
(2)时,自己拿一个,对手拿走一个,自己肯定输,(2)对应子状态(1)为N,所以(2)为P
(3)时,对应子状态为(2)状态为P,所以(3)为N
(4)时,对应子状态为(0)-》P,(3)-》N,考虑到每个人会选择最佳策略,为了赢选择P(0),此时变为N
(5)时,可以选择拿1个,对应(4)为N 拿4个,对应(1)为N,都是先手赢,所以(5)为P,是后手赢
(6)时,可以选择拿1个,对应(5)为P, 拿4个,对应(2)为P,都是后手赢,所以(6)为N,是先手赢
….
以此类推,(17)时,子状态(1) (13) (16)..
N先手赢为1,P后手赢为0,当前石子为n时状态为NIM(n),则状态转移方程为
NIM(n-1) NIM(n-4) NIM(n-16) NIM()… NIM(n)
1 1 1 1 0
0 0 0 0 1
0 0 0 1 1
0 0 1 1 1
核心是
只要子状态包含P后手赢,那么为了赢,一定会选择这个状态为P的子状态,让自己赢
如果子状态都是N先手赢,那么无论怎么做,轮到下一个都必赢,自己一定会输。
import java.util.Scanner;
/**
* Created by Luna on 2017/10/14.
*/
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int loop = input.nextInt();
int c=0;
int[] num = new int[loop];
while (c<loop){
num[c]=input.nextInt();
c++;
}
for (int i = 0; i < loop; i++) {
System.out.println(NIM(num[i])?"niu":"yang");
}
}
public static boolean NIM(int k) {
if (k==0)
return false;
if (k==1)
return true;
int tmp=1;
int count=-1;
while(tmp<=k){ //判断输入值包含4的k次幂,对应有k+1个子状况
if(tmp==k)
return true;
tmp<<=2;
count++;
}
for (int i = 0; i <=count ; i++) {
int next=k - (int)Math.pow(4, i);
if(!NIM(next)) return true; //只要包含false 那么就选择它,让自己赢
}
return false;//如果子状况都是先手赢,那么自己必输。
}
}
运行结果:
5
1
2
3
4
5
niu
yang
niu
niu
yang
5 16 19 31 42 76 niu niu niu yang niu
相关文章推荐
- 百度2017校招java研发在线笔试
- 2015年网易校招Java开发工程师(技术架构)在线笔试题(2015年9月20日 18:00—20:00)
- 2017校招Java开发笔试题集
- 名企笔试:蘑菇街2017校招笔试题(修理桌子问题)2017-03-09 算法爱好者
- 2015年网易校招Java开发工程师(技术架构)在线笔试题
- 【面试笔试算法】Problem 1 : DP滑雪问题--网易互联网算法实习生2017笔试题
- 美团2017校招笔试--取红包问题
- 2016 Java开发 校招笔试回忆(没题 大概内容
- 阿里巴巴2015秋季校招(客户端开发工程师岗位)在线笔试题
- 美团点评2017校招笔试真题-算法工程师A
- 2017阿里巴巴校招在线笔试——货架格子编号
- 算法 博弈问题 取球问题 java
- 【2018校招笔试-京东=java开发】题目1括号匹配方案
- 分金币问题---阿里巴巴2018年校招内推Java研发岗在线编程测验
- 名企笔试:滴滴出行2017秋招笔试(餐馆消费问题)2017-03-06 算法爱好者
- 2015网易校招Java开发工程师(技术架构)在线笔试题
- 2017 360 软件开发 小B乘车看风景问题解答 java
- 2016年腾讯校招在线笔试UI开发总结
- 常见Java问题及笔试题(十七)——阿里2017实习生研发题
- 【在线笔试题解题报告系列】网易2017校招内推笔试之编程题【持续更新】