【蓝桥杯】15届java研究生组E砍柴
一、思路
经典动态规划题目,主要分为两个大步骤:
1.提前计算出范围内的所以质数
2.提前设置dp[1]=0(初始化就为0,不用显式声明),dp[2]=1,然后逐个向后规划,规划过程为从最小的质数开始砍,直到砍完对方必输(为0)即可将当前设为先手必赢,直到砍到负数则不存在先手能赢的情况,即先手必输。
二、记忆
1.动态规划的思路
2.由于蓝桥杯采用连续多个输入,所以我们可以提前预处理好所有的的质数/砍数情况,后面就只用访问数组即可
3.质数检查代码
private static boolean isPrime(int num) {
if(num<=1) {
return false;
}else if(num ==2) {//2是唯一的偶质数
return true;
}else if(num%2 == 0) {//偶数必然不是质数
return false;
}else {
for(int i =3;i*i<=num;i=i+2) {
if(num%i==0) return false;
}
}
return true;
}
三、代码
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
ArrayList<Integer> prime = new ArrayList();
for(int i =2;i<100001 ;i++) {//列出所有质数
if(isPrime(i)) {
prime.add(i);
//System.out.println(i);
}
}
int[] dp = new int[100001];//dynamic plan
//dp[1]=0; //默认就为0了,不用显式声明
dp[2]=1;
//动态规划,先手可以赢则返回1,不能赢则返回0
for(int i = 3;i<100001;i++) {
for(int j = 0 ; j < prime.size();j++) {
int temp = i-prime.get(j);//千万注意关键变量的使用,这里一开始又用成i了
if(temp<0) {
//dp[i]=0;//已经无法找到可以先手砍的情况
break;
}
if(dp[temp]==0) {//说明存在先手赢的情况,当前i置为必赢1
dp[i]=1;
break;
}
}
}
int n = in.nextInt();
for(int i=0;i<n;i++) {
System.out.println(dp[in.nextInt()]==1?1:0);
}
}
private static boolean isPrime(int num) {
if(num<=1) {
return false;
}else if(num ==2) {//2是唯一的偶质数
return true;
}else if(num%2 == 0) {//偶数必然不是质数
return false;
}else {
for(int i =3;i*i<=num;i=i+2) {
if(num%i==0) return false;
}
}
return true;
}