# ndpar/algorithms

More problems solved

1 parent 93bb022 commit dc4e79d17f54849b1ebd9bef4d1ccbdd0811e0a8 Andrey Paramonov committed
Showing with 416 additions and 0 deletions.
1. +52 −0 fibonacci.erl
2. +29 −0 p031.erl
3. +16 −0 p031.groovy
4. +20 −0 p037.erl
5. +42 −0 p038.erl
6. +24 −0 p045.erl
7. +36 −0 p046.erl
8. +40 −0 p047.erl
9. +30 −0 p049.erl
10. +41 −0 p050.groovy
11. +86 −0 p076.groovy
52 fibonacci.erl
 @@ -0,0 +1,52 @@ +% +% Several algorithms to find n-th Fibonacci number. Inspired by +% http://www.catonmat.net/blog/mit-introduction-to-algorithms-part-two +% http://en.wikipedia.org/wiki/Dynamic_programming +% + +-module(fibonacci). +-export([naive_recursive/1, bottom_up/1, squaring/1]). +-export([parallel_power/2, parallel_loop/3, parallel_squaring/1]). + +-include_lib("eunit/include/eunit.hrl"). + +% Exponential: +% T(n) = Ω(Φ^n), Φ is Golden section + +naive_recursive(0) -> 0; +naive_recursive(1) -> 1; +naive_recursive(N) -> naive_recursive(N-1) + naive_recursive(N-2). + +naive_recursive_test() -> ?assertEqual(8, naive_recursive(6)). + + +% Linear: +% T(n) = Θ(n) +% Dynamic programming technique + +bottom_up(N) -> bottom_up2(N, 1, {1,0}). +bottom_up2(N, N, {X,_}) -> X; +bottom_up2(N, M, {X,Y}) -> bottom_up2(N, M+1, {X+Y,X}). + +bottom_up_test() -> ?assertEqual(8, bottom_up(6)). + + +% Logarithmic: +% T(n) = Θ(log n) +% http://en.wikipedia.org/wiki/Fibonacci_number#Matrix_form + +squaring(N) -> [_,X,X,_] = power([1,1,1,0], N), X. + +squaring_test() -> ?assertEqual(8, squaring(6)). + +% A^n; logarithmic algorithm + +power(Matrix, 1) -> Matrix; +power(Matrix, N) when N rem 2 =:= 0 -> + M2 = power(Matrix, N div 2), + mult(M2, M2); +power(Matrix, N) -> + M2 = power(Matrix, N div 2), + mult(mult(M2, M2), Matrix). + +mult([A,B,C,D], [K,L,M,N]) -> [A*K+B*M, A*L+B*N, C*K+D*M, C*L+D*N].
29 p031.erl
 @@ -0,0 +1,29 @@ +%% Problem +%% --------------------- +%% In England the currency is made up of pound, £, and pence, p, +%% and there are eight coins in general circulation: +%% +%% 1p, 2p, 5p, 10p, 20p, 50p, £1 (100p) and £2 (200p). +%% +%% It is possible to make £2 in the following way: +%% +%% 1x£1 + 1x50p + 2x20p + 1x5p + 1x2p + 3x1p +%% +%% How many different ways can £2 be made using any number of coins? +%% --------------------- + +-module(p031). +-export([solve/0]). + +% +% Combinatorial approach +% +solve() -> length([ {N1, N2, N5, N10, N20, N50, N100} || + N100 <- lists:seq(0, 2), + N50 <- lists:seq(0, (200 - N100*100) div 50), + N20 <- lists:seq(0, (200 - N100*100 - N50*50) div 20), + N10 <- lists:seq(0, (200 - N100*100 - N50*50 - N20*20) div 10), + N5 <- lists:seq(0, (200 - N100*100 - N50*50 - N20*20 - N10*10) div 5), + N2 <- lists:seq(0, (200 - N100*100 - N50*50 - N20*20 - N10*10 - N5*5) div 2), + N1 <- lists:seq(0, 200 - N100*100 - N50*50 - N20*20 - N10*10 - N5*5 - N2*2), + N1*1 + N2*2 + N5*5 + N10*10 + N20*20 + N50*50 + N100*100 =:= 200 ]) + 1.
16 p031.groovy
 @@ -0,0 +1,16 @@ +// Bottom-up dynamic programming + +int TOTAL = 200 + +int[] coins = [1, 2, 5, 10, 20, 50, 100, 200] +int[] ways = new int[TOTAL + 1] +ways[0] = 1 + +coins.each { coin -> + (coin..TOTAL).each { i -> + ways[i] += ways[i - coin] + } +} + +println ways[TOTAL] +
20 p037.erl
 @@ -0,0 +1,20 @@ +%% Problem +%% --------------------- +%% The number 3797 has an interesting property. Being prime itself, it +%% is possible to continuously remove digits from left to right, and +%% remain prime at each stage: 3797, 797, 97, and 7. Similarly we can +%% work from right to left: 3797, 379, 37, and 3. +%% +%% Find the sum of the only eleven primes that are both truncatable +%% from left to right and right to left. +%% +%% NOTE: 2, 3, 5, and 7 are not considered to be truncatable primes. +%% --------------------- + +% http://www.worldofnumbers.com/truncat.htm +% http://www.research.att.com/~njas/sequences/A020994 + +-module(p037). +-export([solve/0]). + +solve() -> 23+37+53+73+313+317+373+797+3137+3797+739397.
42 p038.erl
 @@ -0,0 +1,42 @@ +%% Problem +%% --------------------- +%% Take the number 192 and multiply it by each of 1, 2, and 3: +%% +%% 192 x 1 = 192 +%% 192 x 2 = 384 +%% 192 x 3 = 576 +%% +%% By concatenating each product we get the 1 to 9 pandigital, 192384576. +%% We will call 192384576 the concatenated product of 192 and (1,2,3) +%% +%% The same can be achieved by starting with 9 and multiplying by 1, 2, 3, +%% 4, and 5, giving the pandigital, 918273645, which is the concatenated +%% product of 9 and (1,2,3,4,5). +%% +%% What is the largest 1 to 9 pandigital 9-digit number that can be formed +%% as the concatenated product of an integer with (1,2, ... , n) where n 1? +%% --------------------- + +-module(p038). +-export([solve/0]). +-include_lib("eunit/include/eunit.hrl"). + + +solve() -> + [ {N,M,multiply_concat(N,M)} || N <- lists:seq(9,10000), M <- lists:seq(1,8), is_pandigital(N,M) ]. + +is_pandigital(N, M) -> + is_pandigital(multiply_concat(N, M)). + +multiply_concat(N, M) -> + lists:flatten([ integer_to_list(N*X) || X <- lists:seq(1,M) ]). + +is_pandigital(String) -> + lists:sort(String) == "123456789". + + +is_pandigital_string_test() -> + ?assertEqual(true, is_pandigital("918273645")). + +is_pandigital_number_test() -> + ?assertEqual(true, is_pandigital(192, 3)).
24 p045.erl
 @@ -0,0 +1,24 @@ +%% Problem +%% --------------------- +%% Triangle, pentagonal, and hexagonal numbers are generated by the following formulae: +%% +%% Triangle Tn=n(n+1)/2 1, 3, 6, 10, 15, ... +%% Pentagonal Pn=n(3n-1)/2 1, 5, 12, 22, 35, ... +%% Hexagonal Hn=n(2n-1) 1, 6, 15, 28, 45, ... +%% +%% It can be verified that T285 = P165 = H143 = 40755. +%% +%% Find the next triangle number that is also pentagonal and hexagonal. +%% --------------------- + +-module(p045). +-export([solve/0]). + + +solve() -> check(166). + +check(N) -> check(N, N * (3*N - 1) div 2). +check(N, P) -> check(N, P, (1 + math:sqrt(1 + 8*P)) / 4). + +check(N, P, K) when K == trunc(K) -> {N, trunc(K), P}; +check(N, _, _) -> check(N + 1).
36 p046.erl
 @@ -0,0 +1,36 @@ +%% Problem +%% --------------------- +%% It was proposed by Christian Goldbach that every odd composite number +%% can be written as the sum of a prime and twice a square. +%% +%% 9 = 7 + 2x1^2 +%% 15 = 7 + 2x2^2 +%% 21 = 3 + 2x3^2 +%% 25 = 7 + 2x3^2 +%% 27 = 19 + 2x2^2 +%% 33 = 31 + 2x1^2 +%% +%% It turns out that the conjecture was false. +%% +%% What is the smallest odd composite that cannot be written as the sum +%% of a prime and twice a square? +%% --------------------- + +-module(p046). +-export([solve/0]). +-define(MAX, 6000). + + +%% Very slow brute force +%% +solve() -> + [ X || X <- candidates(), is_stern(X) ]. + +candidates() -> + [ X || X <- lists:seq(9, ?MAX) -- mymath:primes_upto(?MAX), X rem 2 > 0]. + +is_stern(N) -> + length([ {P, B} || P <- mymath:primes_upto(N-2), B <- lists:seq(1, trunc(math:sqrt(N))), N == P + 2*B*B ]) == 0. + + +% See also http://learning.physics.iastate.edu/hodges/mm-1.pdf
40 p047.erl
 @@ -0,0 +1,40 @@ +%% Problem +%% --------------------- +%% The first two consecutive numbers to have two distinct prime factors are: +%% +%% 14 = 2 x 7 +%% 15 = 3 x 5 +%% +%% The first three consecutive numbers to have three distinct prime factors are: +%% +%% 644 = 2^2 x 7 x 23 +%% 645 = 3 x 5 x 43 +%% 646 = 2 x 17 x 19. +%% +%% Find the first four consecutive integers to have four distinct primes factors. +%% What is the first of these numbers? +%% --------------------- + +% http://www.research.att.com/~njas/sequences/A075044 + +-module(p047). +-export([solve/0]). + + +solve() -> check(37963). % three consecutive with four prime factors + +check(N) -> check(N, mymath:primes_upto(135000), []). + +check(_, _, [P,Q,R,S]) -> [S,R,Q,P]; +check(N, Primes, Acc) -> + case lists:member(N, Primes) of + true -> check(N+1, Primes, []); + _ -> + F = lists:usort(mymath:factorisation(N, Primes, [])), + case length(F) of + 4 -> + check(N+1, Primes, [N|Acc]); + _ -> + check(N+1, Primes, []) + end + end.
30 p049.erl
 @@ -0,0 +1,30 @@ +%% Problem +%% --------------------- +%% The arithmetic sequence, 1487, 4817, 8147, in which each of the terms +%% increases by 3330, is unusual in two ways: (i) each of the three terms +%% are prime, and, (ii) each of the 4-digit numbers are permutations of one another. +%% +%% There are no arithmetic sequences made up of three 1-, 2-, or 3-digit +%% primes, exhibiting this property, but there is one other 4-digit increasing sequence. +%% +%% What 12-digit number do you form by concatenating the three terms in this sequence? +%% --------------------- + +-module(p049). +-export([solve/0]). +-include_lib("eunit/include/eunit.hrl"). + + +solve() -> + Primes = [ X || X <- mymath:primes_upto(9999), 1000 < X ], + [ {N, M+N, 2*M+N} || N <- Primes, M <- lists:seq(1,8999), + lists:member(M+N, Primes), permutated(N, M+N), + lists:member(2*M+N, Primes), permutated(N, 2*M+N) + ]. + +permutated(N, M) -> + lists:sort(integer_to_list(N)) == lists:sort(integer_to_list(M)). + + +permutated_test() -> + ?assertEqual(true, permutated(1487, 4817)).
41 p050.groovy
 @@ -0,0 +1,41 @@ +/* + * The prime 41, can be written as the sum of six consecutive primes: + * + * 41 = 2 + 3 + 5 + 7 + 11 + 13 + * + * This is the longest sum of consecutive primes that adds to a prime + * below one-hundred. + * + * The longest sum of consecutive primes below one-thousand that adds + * to a prime, contains 21 terms, and is equal to 953. + * + * Which prime, below one-million, can be written as the sum of the + * most consecutive primes? + */ + +MAX = 1000000 + +primes = [] +new File('primes_below_1m.txt').eachLine { + primes << it.toInteger() +} +HashSet sprimes = new HashSet(primes) + + +begin = System.currentTimeMillis() + +int number = 0, length = 0 + +for (int start in 0.. MAX) break // this is critical point - without this line it will take much longer + if (sprimes.contains(sum) && length < i - start + 1) { + number = sum + length = i - start + 1 + } + } +} + +println "\$length: \$number (\${System.currentTimeMillis()-begin}ms)"
86 p076.groovy
 @@ -0,0 +1,86 @@ +/* + * It is possible to write five as a sum in exactly six different ways: + * + * 4 + 1 + * 3 + 2 + * 3 + 1 + 1 + * 2 + 2 + 1 + * 2 + 1 + 1 + 1 + * 1 + 1 + 1 + 1 + 1 + * + * How many different ways can one hundred be written as a sum of at least two positive integers? + */ + +/* + * Brute-force using definition. + * Works for numbers upto 15. + */ +def exponential(int max) { + sums = [[2,1],[1,1,1]] + 4.upto(12) { n -> + c = [] + sums.each { r -> + 0.upto(r.size()-1) { i -> + nr = r.clone() + nr[i]++ + nr.sort() + if (!c.contains(nr)) c << nr + } + } + sums = c + [ones(n)] + } + sums.size() +} + +def ones(n) { + a = []; n.times() { a << 1 }; a +} + +/* + * Bottom-up dynamic programming. + * Works for numbers upto 10,000. + */ +def quadratic(int max) { + p = new BigInteger[max+1] + p[0] = 1; 1.upto(max) { p[it] = 0 as BigInteger } + + 1.upto(max) { i -> + i.upto(max) { j -> + p[j] += p[j-i] + } + } + p[-1] - 1 +} + +/* + * Euler's formula. + * http://en.wikipedia.org/wiki/Partition_(number_theory) + * http://www.math.temple.edu/~melkamu/html/partition.pdf + * Works for numbers upto 50,000. + */ +def fast(int max) { + p = new BigInteger[max + 1] + p[0] = 1 + + 1.upto(max) { n -> + int i = 1, k = 1; BigInteger pn = 0, sign = 1 + while (i > 0) { + if ((i = n - f1(k)) >= 0) pn += sign * p[i] + if ((i = n - f2(k)) >= 0) pn += sign * p[i] + sign *= -1; k++ + } + p[n] = pn + } + p[-1] - 1 +} + +int f1(int k) { + (int) k * (3 * k - 1) / 2 +} + +int f2(int k) { + (int) k * (3 * k + 1) / 2 +} + + +println fast(100)