Find number of ones to get a number using + and *

28

4

Introduction

Your goal is to find the least number of ones you need to add or multiply together to get the input value, this is A005245.

Input

One positive integer N.

Output

The smallest number of ones that must be added/multiplied to get N.

Sample Input

7

Sample Output

6

Explanation

(1 + 1 + 1) * (1 + 1) + 1 = 7

Because this requires 6 ones, the output is 6

Test cases

 1  1
 2  2
 3  3
 5  5
10  7
20  9
50 12

As this is a challenge, lowest number of bytes wins.

Spyrali Chyuu

Posted 2018-01-28T00:38:32.183

Reputation: 289

4OEIS A005245 – betseg – 2018-01-28T00:46:00.527

9

Welcome to Programming Puzzles and Code Golf! As a first challenge this is OK, but next time please use the Sandbox before posting challenges so you can get feedback!

– betseg – 2018-01-28T00:55:18.250

4I'd suggest modifying this to explicitly state that you're looking for the minimum number of ones required. Otherwise, simply outputting the original number and claiming that it's the number of ones you need to add together would be a valid solution. – Shaggy – 2018-01-28T11:25:03.180

To clarify, you meant "using + and * ". Exponentiation would allow fewer, e.g. 9 = (1 + 1 + 1) ^ (1 + 1) ; uses 5 ones, not 6. – smci – 2018-01-28T21:27:59.893

2Are there examples where f(x) != x.primeFactorisation().sum() except 1? – jrtapsell – 2018-01-28T22:22:23.693

1@jrtapsell: yes. The given example of $f(7)=6$ is one. For any (large enough) prime $p$ you can factor $p-1$ and add one. You may be able to do better yet. – Ross Millikan – 2018-01-29T02:29:05.230

@Ross Fun fact (taken from the oeis page): the smallest prime number p such that f(p) doesn't equal f(p-1)+1 is p=353942783 – Carmeister – 2018-01-29T03:43:46.453

1@jrtapsell: Yes, many primes or pseudoprimes, esp. near multiples of a large power of 2 or 3 might be more compactly written as that power + a small offset. Examples: a) 13 = 223+1 (requires 8) and b) 129 = 2222222 + 1 (requires 15, not 129). Intuitively, the "optimal" factorization will generally involve powers of 2 and 3 such that we are approximating e^x. – smci – 2018-01-29T06:30:27.160

Bonus points if solutions work up to known counterexamples n = 353942783 and n = 516743639 ? – smci – 2018-01-29T06:35:28.617

Answers

17

Python 2, 74 70 bytes

f=lambda n:min([n]+[f(j)+min(n%j*n+f(n/j),f(n-j))for j in range(2,n)])

Try it online!

Alternate version, 59 bytes (unverified)

f=lambda n:min([n]+[f(j)+f(n/j)+f(n%j)for j in range(2,n)])

This works at least up to n = 1,000,000, but I have yet to prove that it works for all positive n.

Try it online!

Dennis

Posted 2018-01-28T00:38:32.183

Reputation: 196 637

Sorry if I'm missing something simple, but it's not obvious to be that this tries every viable expression tree. In particular, we have outer layer n=a*j+b with b<j, but might we need b>=j? – xnor – 2018-01-30T20:45:26.510

Hm, it would only fail if both b>=j and b>=a. But you're right, it's not obvious that this won't happen. – Dennis – 2018-02-01T15:53:19.177

Interesting that there's no counterexamples up to 1,000,000, I wonder if it actually just always works. My best thought for a counterexample would be something of form a*b+c*d with a,b,c,d all summation expressions and are very efficient. – xnor – 2018-02-01T23:58:13.747

10

Jelly, 16 14 bytes

Thanks Dennis for saving 2 bytes!

ÆḌḊ,Ṗ߀€+U$FṂo

Try it online!


Logic explanation

Given a number n:

  • If it's 1, the answer is 1. Otherwise:

The representation is either a + b or a × b, where a and b are expressions.

Consider all possible values of a and b:

  • If the representation is a + b, then a and b are in range [1 .. n-1].
  • If the representation is a × b, a and b are proper divisors of n larger than 1.

In both cases, the list [[<proper divisors of n larger than 1>], [1, 2, ..., n-1]] is computed (ÆḌḊ,Ṗ), map the current link over each number ߀€, add the correct pairs together (+U$) and get the minimum value (FṂo).

Code explanation

ÆḌḊ,Ṗ߀€+U$FṂo   Main link. Assume n = 10.
ÆḌ       Proper divisors. [1,2,5]equeue, remove the first element. [2,5]
   ,Ṗ    Pair with op. Auto convert n = 10 to range 
         [1,2,3,4,5,6,7,8,9,10] and remove the last element
         10, get [1,2,3,4,5,6,7,8,9].

߀€      Apply this link over each element.
   +U$   Add with the Upend of itself.

FṂ       Flatten and get the inimum element.
  o      Logical or with n.
         If the list is empty, minimum returns 0 (falsy), so logical or
         convert it to n.

user202729

Posted 2018-01-28T00:38:32.183

Reputation: 14 620

5

Pari/GP, 66 bytes

A port of Dennis's Python answer:

f(n)=vecmin(concat(n,[f(j)+min(n%j*j+f(n\j),f(n-j))|j<-[2..n-1]]))

Try it online!


Pari/GP, 72 bytes

Longer, but more efficient:

f(n)=if(n<6,n,vecmin([if(d>1,f(d)+f(n/d),1+f(n-1))|d<-divisors(n),d<n]))

Try it online!

alephalpha

Posted 2018-01-28T00:38:32.183

Reputation: 23 988

1Dennis improved his method and using that can save you 11 bytes: f(n)=vecmin(concat(n,[f(j)+f(n\j)+f(n%j)|j<-[2..n-1]])). – Jonathan Allan – 2018-01-28T15:59:57.783

5

JavaScript (ES6), 108 96 bytes

f=n=>n<6?n:Math.min(...[...Array(n-2)].map((_,i)=>Math.min(f(++i)+f(n-i),n%++i/0||f(i)+f(n/i))))

Very inefficient; Array(n>>1) speeds it up slightly at a cost of a byte. Explanation: n%++i is non-zero if i is not a factor, so n%++i/0 is Infinity (and therefore truthy, and also definitely not minimal) if i is not a factor, but NaN (and therefore falsy) if i is a factor. Edit: Saved 12 bytes with inspiration from @edc65.

Neil

Posted 2018-01-28T00:38:32.183

Reputation: 95 035

I tried running this in the background to see whether it was in fact capable of calculating f(50) but unfortunately Windows Update rebooted my PC before it could finish. – Neil – 2018-02-07T10:20:31.127

Did you try a single walk on the a array? – edc65 – 2018-02-19T11:12:33.710

@edc65 Sorry, but I'm unclear as to what you're suggesting and why. – Neil – 2018-02-19T14:13:23.343

I see 2 maps, each one scanning the a array. Can't you merge the evaluations in the 2 lambdas and take the min? – edc65 – 2018-02-19T14:17:21.590

@edc65 Ah yes, for some reason I thought nesting the min wouldn't be cheaper but I get to replace (i+=2) with another ++i so I'm saving 12 bytes in total, thanks! – Neil – 2018-02-19T14:39:38.337

4

Pari/GP, 213 bytes

Edit: I've been severely beaten.

f(n)={d;n<6&return(n);if(n<=#a,a[n]&return(a[n]),a=vector(n));for(i=1,n-1,a[i]||a[i]=f(i));a[n]=min(vecmin(vector(n\2,k,a[k]+a[n-k])),if(isprime(n),n,vecmin(vector((-1+#d=divisors(n))\2,i,a[d[i+1]]+a[d[#d-i]]))))}

Try it online!

MD XF

Posted 2018-01-28T00:38:32.183

Reputation: 11 605

3

Python 2, 181 bytes

def F(N,n,s="",r=""):
 try:
	if n<1:return(eval(s)==N)*0**(`11`in s or"**"in s)*s
	for c in"()+*1":r=F(N,~-n,s+c)or r
 except:r
 return r
f=lambda N,n=1:F(N,n).count(`1`)or f(N,-~n)

Try it online!

Jonathan Frech

Posted 2018-01-28T00:38:32.183

Reputation: 6 681

@pizzapants184 The main function f must not be anonymous, as it calls itself recursively. – Jonathan Frech – 2018-01-28T23:56:31.873

Ah, sorry, I didn't see that. – pizzapants184 – 2018-01-28T23:57:36.513

2

Wolfram Language (Mathematica), 59 bytes

Saved 3 bytes thanks to Martin Ender. Using CP-1252 encoding, where ± is one byte.

±1=1;±n_:=Min[1+±(n-1),±#+±(n/#)&/@Divisors[n][[2;;-2]]]

Try it online!

alephalpha

Posted 2018-01-28T00:38:32.183

Reputation: 23 988

1Does not work correctly for input 353942783. – Misha Lavrov – 2018-10-27T03:00:45.927

1

Perl 5, -p 78 bytes

79 bytes in old style counting (+1 for -p)

The fact that perl must use an extra $ for all scalar access really hurts the length of golfs that do a lot of arithmetic...

This method is mostly like the others already posted (try multiplication and addition to build a target number, take the cheapest). It however doesn't repeatedly recurse down so it can be used for relatively large inputs.

It also doesn't try to minimize the cost of building a number by addition or multip[lication because perl 5 has no builtin min and numeric sort is looooooong (as seen from the sort still in the code). Instead I just assume if a number is a factor of the target that I will use multiplication. That is safe since if e.g. 3 is a factor of 12 (so it sums the cost of 3 and 12/3) later in the loop it will consider 9=12-3 which will not be a factor, so 9+3 with the same cost as 3+9 will get tried anyways. However that may fail for targets <= 4 (it only does for 1 and 2). Adding $_ to the list to minimize fixes that. Which is unfortunate since I don't actually need that for the base cases because I already initialize @; with the proper starting values so it costs 3 bytes.

#!/usr/bin/perl -p
($_)=sort{$a-$b}$_,map{$;[$_]+$;[$'%$_?$'-$_:$'/$_]}//..$_ for@;=0..$_;$_=pop@

Try it online!

Ton Hospel

Posted 2018-01-28T00:38:32.183

Reputation: 14 114