问题:首先100,000,000个六边形数字中有多少可以被1到20之间的所有数字整除?
第二种解决方案 - 简单的蛮力(确实有效)
public static void main(String[] args) {
long hnr = 100000000L, count = 0L;
for (long i = 1, h = getHexNr(i); i <= hnr; i++, h = getHexNr(i))
if (h % 2 == 0 && h % 3 == 0 && h % 4 == 0 && h % 5 == 0
&& h % 6 == 0 && h % 7 == 0 && h % 8 == 0
&& h % 9 == 0 && h % 10 == 0 && h % 11 == 0
&& h % 12 == 0 && h % 13 == 0 && h % 14 == 0
&& h % 15 == 0 && h % 16 == 0 && h % 17 == 0
&& h % 18 == 0 && h % 19 == 0 && h % 20 == 0) count++;
System.out.println(count);
}
第一个解决方案(不起作用)
public static void main(String[] args) {
long nr = 1L, hnr = 100000000L, count = 0L;
double tmp = 0;
for (long i = 2L; i < 21; i++)
nr = lcm(nr, i);
for (double qes : getQES(2, 1, -nr)) {
if (qes < 0) continue;
int limit = (int) (getHexNr(hnr) / Math.floor(qes));
for (int i = 0; i < limit; i++) {
// if ((i * qes) % 1 == 0) count++;
if ((tmp += qes) % 1 == 0) count++;
}
}
System.out.println(count);
}
和utils:
static long gcd(long a, long b) {
if (b == 0) return Math.abs(a);
return gcd(b, a % b);
}
static long lcm(long a, long b) {
return (a * b) / gcd(a, b);
}
static long getHexNr(long n) {
return n * (2 * n - 1);
}
static double[] getQES(long a, long b, long c) {
double d = b * b - 4 * a * c;
if (d < 0) return new double[0];
return new double[] { (-b + Math.sqrt(d)) / (2 * a),
(-b - Math.sqrt(d)) / (2 * a) };
}
编辑: 解决方案1的算法:
编辑2:
编辑3:
是的,蛮力版本应该只检查21岁以下素数的可分性。但更有意思的是找出戈德伯格所说的内容。我确实知道,但更像是five monkeys story。
稍后,当我记得时,我想到舍入数字,数学库不包含执行此操作的功能。但我可以使用BigDecimal,当我查找BigDecimal并加倍我找到this。多么令人愉快的似曾相识。
四舍五入看起来像:
public static double round(double d, int nr) {
return new BigDecimal(Double.toString(d)).setScale(nr,
BigDecimal.ROUND_HALF_UP).doubleValue();
}
答案 0 :(得分:2)
虽然可能还有其他问题:
((tmp += qes) % 1 == 0)
tmp和qes都是双打,这意味着==比较可能会失败;见What Every Computer Scientist Should Know About Floating-Point Arithmetic
答案 1 :(得分:0)
您应该链接到描述问题,以便人们可以知道六角形数字是什么。
同样在蛮力方法中,您不需要重新检查数字中的常见素因子,因为所有这些都必须是可分的,所以它可以缩短为:
public static void main(String[] args) {
long hnr = 100000000L, count = 0L;
for (long i = 1, h = getHexNr(i); i <= hnr; i++, h = getHexNr(i))
if (h % 20 == 0 && h % 19 == 0 && h % 18 == 0 && h % 17 == 0
&& h % 16 == 0 && h % 14 == 0 && h % 13 == 0 && h % 11 == 0) count++;
System.out.println(count);
}
我很好奇,所以我把结果计时:
include <stdio.h>
#define H(n) (n*(2ULL*n-1ULL))
#define limit 100000000ULL
int main(int argc, char** argv){
unsigned long long int count=0, i = 1, h = 1;
if(argc>1&&argv[1][0]=='1'){
for (; ++i <= limit; h = H(i)) {
if (h % 19 == 0 && h % 17 == 0 && h % 16 == 0 && h % 13 == 0
&& h % 11 == 0 && h % 9 == 0 && h % 7 == 0 && h % 5 == 0) count++;
}
} else if(argc>1&&argv[1][0]=='2'){
for (; ++i <= limit; h = H(i)) {
if (h % 20 == 0 && h % 19 == 0 && h % 18 == 0 && h % 17 == 0
&& h % 16 == 0 && h % 14 == 0 && h % 13 == 0 && h % 11 == 0) count++;
}
} else if(argc>1&&argv[1][0]=='3'){
for (; ++i <= limit; h = H(i)) {
if (h % 5 == 0 && h % 7 == 0 && h % 9 == 0 && h % 11 == 0
&& h % 13 == 0 && h % 16 == 0 && h % 17 == 0 && h % 19 == 0) count++;
}
} else if(argc>1&&argv[1][0]=='4'){
for (; ++i <= limit; h = H(i)) {
if (h % 11 == 0 && h % 14 == 0 && h % 14 == 0 && h % 16 == 0
&& h % 17 == 0 && h % 18 == 0 && h % 19 == 0 && h % 20 == 0) count++;
}
} else {
for (; ++i <= limit; h = H(i)) {
if (h % 2 == 0 && h % 3 == 0 && h % 4 == 0 && h % 5 == 0
&& h % 6 == 0 && h % 7 == 0 && h % 8 == 0
&& h % 9 == 0 && h % 10 == 0 && h % 11 == 0
&& h % 12 == 0 && h % 13 == 0 && h % 14 == 0
&& h % 15 == 0 && h % 16 == 0 && h % 17 == 0
&& h % 18 == 0 && h % 19 == 0 && h % 20 == 0) count++;
}
}
printf("%llu\n",count);
}
方法1略快于2,方法4略快于3.方法3或4比1或2快,原始速度更快。奇?
投掷h%2 == 0&amp;&amp;在所有方法面前,我得到了更好的结果;原始(仍然是相同的速度)现在比所有这些都慢,但否则排名保持不变。 gcc
必须优化h%2==0
才能成为按位操作。
所有输出59
并在我的2.1Ghz Core Duo便携式设备上运行约2秒钟。