Project Euler Problem 387 - Harshad Numbers - 深度优先

原题

A Harshad or Niven number is a number that is divisible by the sum of its digits. 201 is a Harshad number because it is divisible by 3 (the sum of its digits.) When we truncate the last digit from 201, we get 20, which is a Harshad number. When we truncate the last digit from 20, we get 2, which is also a Harshad number. Let's call a Harshad number that, while recursively truncating the last digit, always results in a Harshad number a right truncatable Harshad number.

Also: 201/3=67 which is prime. Let's call a Harshad number that, when divided by the sum of its digits, results in a prime a strong Harshad number.

Now take the number 2011 which is prime. When we truncate the last digit from it we get 201, a strong Harshad number that is also right truncatable. Let's call such primes strong, right truncatable Harshad primes.

You are given that the sum of the strong, right truncatable Harshad primes less than 10000 is 90619.

Find the sum of the strong, right truncatable Harshad primes less than 10<sup>14<sup>.

分析

Harshad Numbers(哈沙德数)

是可以在某个固定的进位制中,被其数位的数字之和整除的整数。

  • right truncatable Harshad number :循环截掉哈沙德数右边一个数字,新数字还是哈沙德数

  • strong Harshad number:如果哈沙德数与它的各位数字之和的比值是素数。

  • strong, right truncatable Harshad primes 是这样一类素数,去掉最后一个数字后,是一个strong Harshad number也是一个right truncatable Harshad number

穷举法有两条思路:

  • 思路一:基于素数搜索。 从11开始遍历下一个素数,判断它是不是满足条件的素数,把满足条件的素数相加直到10<sup>14</sup>;
  • 思路二:基数哈沙德数搜索。 从数字1 ~ 9开始(1 ~ 9都是哈沙德数),深度遍历搜索哈沙德数,在哈沙德数基础上递归搜索这个数末尾加上0~9之后是否素数,是否是哈沙德数,以此遍历下去。每次在末尾添加0 ~ 9 可以保证哈沙德数都是right truncatable的,无需而外运算。

实践证明,思路一不可行,10^14以内的素数不是短时间内可以遍历完的,而且对每个素数进行条件判断也比较耗时。思路二可行。

解题

基数哈沙德数深度优先搜索

static long N = (long) Math.pow(10, 14);
    /**
     * 按照 Truncatable HarshadNumber遍历:
     * @param n a Right Truncatable HarshadNumber
     * @param ds sum of digits of n
     * @param strong n is strong HarshadNumber
     * @return 以n为前缀的所有StrongRightTruncatableHarshad素数之和
     */
    public static long sumHarshadNumber(long n, int ds, boolean strong) {
        n = n * 10;
        if (n >= N) {
            return 0;
        }
        long sum = 0;
        for (int i = 0; i <= 9; i++) {
            n += i; // new n
            ds += i;// new ds
            if (strong && Util.isProbablePrime(n, 100)) {// new n is prime
                sum += n;
            }
            if (n % ds == 0) { // new n is a Right Truncatable HarshadNumber,recursive
                sum += sumHarshadNumber(n, ds, Util.isProbablePrime(n / ds, 100));
            }
            n -= i;// restore n
            ds -= i;// restore ds
        }
        return sum;
    }

其中,Util.isProbablePrime 如下:

    /**
     * 判断v是否可能是素数,是素数的概率为:1-1/2^certainty
     * @return
     */
    public static boolean isProbablePrime(long v, int certainty) {
        return BigInteger.valueOf(v).isProbablePrime(certainty);
    }

求和

    public static void main(String[] args) {
        long s = System.nanoTime();
        System.out.println(sumHarshadNumbes());
        System.out.println("Time consumed : " + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - s) + " ms");
    }
    public static long sumHarshadNumbers() {
        long sum = 0;
        for (int i = 1; i < 9; i++) {
            sum += sumHarshadNumber(i, i, false);
        }
        return sum;
    }

输出

696067597313468
Time consumed : 168 ms

转载于:https://my.oschina.net/cwjcsu/blog/516968

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值