一、题目一
取球博弈
两个人玩取球的游戏。
一共有N个球,每人轮流取球,每次可取集合{n1,n2,n3}中的任何一个数目。
如果无法继续取球,则游戏结束。
此时,持有奇数个球的一方获胜。
如果两人都是奇数,则为平局。
假设双方都采用最聪明的取法,
第一个取球的人一定能赢吗?
试编程解决这个问题。
输入格式:
第一行3个正整数n1 n2 n3,空格分开,表示每次可取的数目 (0<n1,n2,n3<100)
第二行5个正整数x1 x2 ... x5,空格分开,表示5局的初始球数(0<xi<1000)
输出格式:
一行5个字符,空格分开。分别表示每局先取球的人能否获胜。
能获胜则输出+,
次之,如有办法逼平对手,输出0,
无论如何都会输,则输出-
例如,输入:
1 2 3
1 2 3 4 5
程序应该输出:
+ 0 + 0 -
再例如,输入:
1 4 5
10 11 12 13 15
程序应该输出:
0 - 0 + +
再例如,输入:
2 3 5
7 8 9 10 11
程序应该输出:
+ 0 0 0 0
资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 3000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.7及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。
二、思路
最优取法:先取最大的奇数球,在没有或无法取到最大的奇数球时就取最大的取球数。
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int[] a = new int[5];// 球总数
int[] b = new int[3];// 能取球数
for (int i = 0; i < 3; i++) {
b[i] = sc.nextInt();
}
for (int i = 0; i < 5; i++) {
a[i] = sc.nextInt();
}
for (int i = 0; i < 3; i++) {// 给能取球数从大到小排列
for (int j = 0; j < 3 - i - 1; j++) {
if (b[j] > b[j + 1]) {
int t = b[j];
b[j] = b[j + 1];
b[j + 1] = b[j];
}
}
}
for (int i = 0; i < 5; i++) {
int x = 0, y = 0;// x第一个人的总球数,y第二个人的总球数
while (a[i] != 0) {
if (b[0] > a[i])
break;// 剩余的球比可取的最小数还小,则结束
boolean x1 = false, y1 = false;// 标记能不能取到奇数,true代表能
for (int j = 2; j >= 0; j--) {
if ((x % 2 == 0 && b[j] % 2 == 0) || (x % 2 != 0 && b[j] % 2 != 0)) {// 取得球数和已有球数不能都为奇数,也不能都为偶数
continue;
}
if (b[j] > a[i])//剩余的球比可取的最小数还小,则结束
continue;
x += b[j];
a[i] -= b[j];
x1 = true;
break;
}
if (!x1) {// 如果不能保证为奇数 取出一个最大的数
for (int j = 2; j >= 0; j--) {
if (b[j] > a[i])//取出的球数比剩余球数还要大,则结束本次循环
continue;
x += b[j];
a[i] -= b[j];
}
}
for (int j = 2; j >= 0; j--) {// 第二个人与第一个人取法上
if ((y % 2 == 0 && b[j] % 2 == 0) || (y % 2 != 0 && b[j] % 2 != 0)) {
continue;
}
if (b[j] > a[i])//剩余的球比可取的最小数还小,则结束本次循环
continue;
y += b[j];
a[i] -= b[j];
y1 = true;
break;
}
if (!y1) {
for (int j = 2; j >= 0; j--) {
if (b[j] > a[i])
continue;
y += b[j];
a[i] -= b[j];
}
}
}
if (y == 0) {
if (x == 0)
System.out.print(0 + " ");
else
System.out.print("+" + " ");
} else if (y % 2 == 0 && x % 2 != 0) {
System.out.print("+" + " ");
} else if (y % 2 != 0 && x % 2 == 0) {
System.out.print("-" + " ");
} else if (y % 2 == 0 && x % 2 == 0) {
System.out.print(0 + " ");
} else {
System.out.print(0 + " ");
}
}
}
三、题目二
问题描述
今盒子里有n个小球,A、B两人轮流从盒中取球,每个人都可以看到另一个人取了多少个,
也可以看到盒中还剩下多少个,并且两人都很聪明,不会做出错误的判断。
我们约定:
每个人从盒子中取出的球的数目必须是:1,3,7或者8个。
轮到某一方取球时不能弃权!
A先取球,然后双方交替取球,直到取完。
被迫拿到最后一个球的一方为负方(输方)
请编程确定出在双方都不判断失误的情况下,对于特定的初始球数,A是否能赢?
程序运行时,从标准输入获得数据,其格式如下:
先是一个整数n(n<100),表示接下来有n个整数。然后是n个整数,每个占一行(整数<10000),表示初始球数。
程序则输出n行,表示A的输赢情况(输为0,赢为1)。
例如,用户输入:
4
1
2
10
18
则程序应该输出:
0
1
1
0
*/
###四、分析
(一)、找规律。
一个人可以取1,3,7,8三种数量的球。
当总球数为1,先手取球只能取1,输
当总球数为2,先手取球为1,赢
当总球数为3,先手取球为1或3,都输
当总球数为4,先手取球为3,赢
当总球数为5,先手取球为1或3,都输
当总球数为6,先手取球为3,赢
当总球数为7,也是输
当总球数为8,先手取7,赢
当总球数为9,先手取8,赢
当总球数为10,先手取7,赢
就这样一直到16,会发现以15为一个循环,当总球数对15求余为1,3,5,7时,先手比输。
public class Test3 {
static Scanner scanner = new Scanner(System.in);
public static void main(String[] args) {
int n = scanner.nextInt();
int a[] = new int[10001];
for (int i = 0; i < a.length; i++) {
//对15求余,余数为1,3,5,7则先手输
if (i % 15 == 1 || i % 15 == 3 || i % 15 == 5 || i % 15 == 7) {
a[i] = 1;
}
}
Vector<Integer> vector = new Vector<Integer>();
for (int i = 0; i < n; i++) {
vector.add(scanner.nextInt());
}
for (Iterator<Integer> iterator = vector.iterator(); iterator.hasNext();) {
Integer integer = (Integer) iterator.next();
if(a[integer]==1){
System.out.println(0);
}else{
System.out.println(1);
}
}
}
}
(二)、动态规划。
array[i]代表初始球数为i时,先取球的A的输赢情况,那么array[i]和array[i-1],array[i-3],array[i-7],array[i-8]之间的关系是,array[i]=!array[i-1] || !array[i-3] || !array[i-7] || !array[i-8],因为当array[i-1,3,7,8]为false时,array[i]必定为true.
static boolean array[] = new boolean[10020];
public static void main(String[] args) {
//array[i]代表初始球数为i时,先取球的A的输赢情况
array[0] = true;
for (int i = 1; i < array.length; i++) {
array[i] = (i >= 8 && !array[i - 8]) || (i >= 7 && !array[i - 7]) || (i >= 3 && !array[i - 3])
|| (i >= 1 && !array[i - 1]);
}
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int total;
scanner.nextLine();
while ((n--) > 0) {
total = scanner.nextInt();
System.out.println(array[total] ? 1 : 0);
}
}
Travel hopefully is a better thing than to arrive,and true success is to labour.