《程序员的算法趣题》-(日)增井敏克 , 书中为69 道数学谜题编写了解题程序, 编程语言为:Ruby,JavaScript,C语言。
Q18 水果酥饼日
日本每月的 22 日是水果酥饼日。因为看日历的时候, 22 日的上方刚好是 15日,也就是“‘22’这个数字上面点缀着草莓”(如果将日语的 15 拆为 1 和 5发音,则与日语“草莓”一词发音相同,而水果酥饼中最为著名的就是草莓酥饼。)
切分酥饼的时候,要求切分后每一块上面的草莓个数都不相同。假设切分出来的 N 块酥饼上要各有“1~N 个(共 N(N + 1)÷2 个草莓)”。但这里要追加一个条件,那就是“一定要使相邻的两块酥饼上的数字之和是平方数”。
举个例子,假设 N = 4 时采用如 图的切法。这时,虽然 1 + 3 =4 得到的是平方数,但“1 和 4” “2和 3” “2 和 4”的部分都不满足条件。
问题
求可以使切法满足条件的最小的 N(N > 1)。
public class lb12_25_水果酥饼日 {
public static int printMinN() {
int N = 2;
while (true) {
int[] useList = new int[N - 1];
for (int i = 2; i < N + 1; i++) {
useList[i - 2] = i;
}
// 枚举4,9...平方数,事先计算平方数(最大值为n 的2 倍)
int len = (int) (Math.sqrt(N * 2)) + 2;
int sqrt[] = new int[len];
for (int i = 0; i < len; i++) {
sqrt[i] = (i + 1) * (i + 1);
}
if (check(1, useList, sqrt)) {
break;
}
N += 1;
}
return N;
}
static List<Integer> list = new ArrayList<>();
public static boolean check(int start, int[] useList, int[] sqrt) {
for (int i = 0; i < useList.length; i++) {
int number = useList[i];
if (number == 0) {
continue;
}
if (containsNum(number + start, sqrt)) {
if (useList[useList.length - 1] == 14) {
list.add(number);
}
useList[i] = 0;
boolean isZero = true;
for (int n : useList) {
if (n != 0) {
isZero = false;
break;
}
}
// 最后一个number跟1相加
if (isZero && containsNum(number + 1, sqrt)) {
return true;
}
if (check(number, useList, sqrt)) {
return true;
} else {
// 还原被修改的useList
useList[i] = number;
}
}
}
return false;
}
public static boolean containsNum(int number, int[] sqrt) {
for (int i = 0; i < sqrt.length; i++) {
if (number == sqrt[i]) {
return true;
}
}
return false;
}
public static void main(String[] args) {
System.out.println(printMinN());
System.out.println(list);
}
}
参考:https://blog.csdn.net/cloudly89/article/details/84846650