Des produits qui équivalent à une somme et vice versa

22

Une paire amusante d'équivalences est 1 + 5 = 2 · 3 et 1 · 5 = 2 + 3 . Il y en a beaucoup comme ceux-ci, un autre est 1 + 1 + 8 = 1 · 2 · 5 et 1 · 1 · 8 = 1 + 2 + 5 . En général, un produit de n entiers positifs est égal à une somme de n entiers positifs, et vice versa.

Dans ce défi, vous devez générer toutes ces combinaisons d'entiers positifs pour une entrée n> 1 , à l'exclusion des permutations. Vous pouvez les afficher dans n'importe quel format raisonnable. Par exemple, toutes les solutions possibles pour n = 3 sont:

(2, 2, 2) (1, 1, 6)
(1, 2, 3) (1, 2, 3)
(1, 3, 3) (1, 1, 7)
(1, 2, 5) (1, 1, 8)

Le programme qui peut générer le plus de combinaisons pour le n le plus élevé en une minute sur mes 2 Go de RAM , un ordinateur portable Intel Ubuntu 64 bits gagne. Si votre réponse utilise plus de 2 Go de RAM ou est écrite dans une langue que je ne peux pas tester avec un logiciel disponible gratuitement, je ne noterai pas votre réponse. Je vais tester les réponses dans deux semaines et choisir le gagnant. Les réponses non concurrentes ultérieures peuvent toujours être publiées bien sûr.

Comme on ne sait pas quels sont les ensembles complets de solutions pour tous les n , vous êtes autorisé à publier des réponses qui génèrent des solutions incomplètes. Cependant, si une autre réponse génère une solution (plus) complète, même si leur n maximum est plus petit , cette réponse l'emporte.


Pour clarifier, voici le processus de notation pour décider du gagnant:

  1. Je vais tester votre programme avec n = 2, n = 3, etc ... Je stocke toutes vos sorties et m'arrête lorsque votre programme prend plus d'une minute ou plus de 2 Go de RAM. Chaque fois que le programme est exécuté pour une entrée donnée n, il sera interrompu s'il prend plus d'une minute.

  2. Je regarde tous les résultats pour tous les programmes pour n = 2. Si un programme a produit des solutions moins valides qu'un autre, ce programme est éliminé.

  3. Répétez l'étape 2 pour n = 3, n = 4, etc ... Le dernier programme en attente l'emporte.

orlp
la source
1
Donc pas de réponses dans des langues exclusives à Windows?
Conor O'Brien
3
Personnellement, je n'aime pas les critères de notation. Il est impossible de savoir si nos solutions fonctionneront et où définir les seuils tant que nous n'aurons pas les résultats des tests sur votre ordinateur. Je pense qu'un simple code-golf ferait une meilleure question.
musicman523
2
Je suppose que le codage en dur n'est pas autorisé. Mais alors cette restriction est presque inobservable
Luis Mendo
1
@ user202729 Non, je dois essayer chaque programme pour chaque n pour voir quel programme génère plus de solutions.
orlp
2
"Dans deux semaines" est il y a 3 jours.
GB

Réponses:

4

C (gcc) , n = 50000000 avec 6499 résultats en 59 s

Pour éviter de produire plus d'un téraoctet de sortie composé presque entièrement de 1s, une séquence de (disons) 49999995 1s est abrégée en 1x49999995.

#include <stdio.h>
#include <stdlib.h>

static int n, *a1, k1 = 0, *a2, k2 = 0, s1, p1, *factor;

static void out() {
  if (s1 == p1) {
    for (int i = 0; i < k1 && i < k2; i++) {
      if (a1[i] < a2[i])
        return;
      else if (a1[i] > a2[i])
        break;
    }
  }

  for (int i = 0; i < k1; i++)
    printf("%d ", a1[i]);
  printf("1x%d | ", n - k1);
  for (int i = 0; i < k2; i++)
    printf("%d ", a2[i]);
  printf("1x%d\n", n - k2);
}

static void gen2(int p, int s, int m);

static void gen3(int p, int s, int m, int x, int q) {
  int r = s - n + k2 + 2;
  int d = factor[q];
  do {
    if (x * d <= m)
      x *= d;
    q /= d;
  } while (q % d == 0);
  do {
    if (q == 1) {
      a2[k2++] = x;
      gen2(p / x, s - x, x);
      k2--;
    } else {
      gen3(p, s, m, x, q);
    }
    if (x % d != 0)
      break;
    x /= d;
  } while (p / (x * q) >= r - x * q);
}

static void gen2(int p, int s, int m) {
  int n2 = n - k2;
  if (p == 1) {
    if (s == n2)
      out();
  } else if (n2 >= 1 && m > 1) {
    int r = s - n2 + 1;
    if (r < 2 || p < r)
      return;
    if (m > r)
      m = r;
    if (factor[p] <= m)
      gen3(p, s, m, 1, p);
  }
}

static void gen1(int p, int s, int m) {
  int n1 = n - k1;
  p1 = p;
  s1 = s + n1;
  gen2(s1, p1, s + n1 + 1 - n);
  if (n1 != 0) {
    int *p1 = &a1[k1++];
    for (int x = 2; x <= m && p * x <= s + x + n1 - 1; x++) {
      *p1 = x;
      gen1(p * x, s + x, x);
    }
    k1--;
  }
}

int main(int argc, char **argv) {
  if (argc < 2)
    return 1;
  n = atoi(argv[1]);
  if (n < 2)
    return 1;
  a1 = malloc(n * sizeof(int));
  a2 = malloc(n * sizeof(int));
  factor = calloc(4 * n - 1, sizeof(int));
  for (int p = 2; p < 4 * n - 1; p++)
    if (factor[p] == 0) {
      factor[p] = p;
      for (int i = p; i <= (4 * n - 2) / p; i++)
        factor[p * i] = p;
    } else if (factor[p] < factor[p / factor[p]]) {
      factor[p] = factor[p / factor[p]];
    }
  gen1(1, 0, 3 * n - 1);
  return 0;
}

Essayez-le en ligne!

Anders Kaseorg
la source
3

Mathematica, n = 293 avec 12 solutions

OP a changé le défi et demande une entrée
Voici le nouveau code qui prend tout n comme entrée
Pour n = 293, vous obtenez les 12 solutions

If[#<5,Union[Sort/@Select[Tuples[{1,2,3,4,5,6,7,8,9},{#}],Tr@#==Times@@#&]],For[a=1,a<3,a++,For[b=a,b<3,b++,For[c=b,c<5,c++,For[d=c,d<10,d++,For[e=d,e<300,e++,If[Tr[s=Join[Table[1,#-5],{a,b,c,d,e}]]==Times@@s,Print[s]]]]]]]]&


contribution

[n]

Vous pouvez tester cet algorithme sur Wolfram Sandbox qui est un logiciel en ligne disponible gratuitement.
Suivez simplement le lien, collez le code (ctrl + v), collez l'entrée à la fin du code et appuyez sur Maj + Entrée pour exécuter.
Vous obtiendrez toutes mes solutions en quelques secondes

Voici également Essayez-le en ligne!en C ++ (gcc)
(Un grand merci à @ThePirateBay pour avoir supporté et traduit mon code dans un langage gratuit)

ce programme ne génère que des solutions de la forme {a, b, c} {a, b, c}
ce qui signifie a + b + c = a * b * c

Il faut 1 seconde pour calculer

les douze solutions sont:

{1,1 ..., 1,1,1,2,293} {1,1 ..., 1,1,1,2,293}
{1,1 ..., 1,1,1,3,147} {1 , 1 ..., 1,1,1,3,147}
{1,1 ..., 1,1,1,5,74} {1,1 ..., 1,1,1,5,74}
{1,1 ..., 1,1,2,2,98} {1,1 ..., 1,1,2,2,98}
{1,1 ..., 1,1,2, 3,59} {1,1 ..., 1,1,2,3,59}
{1,1 ..., 1,1,2,5,33} {1,1 ..., 1, 1,2,5,33}
{1,1 ..., 1,1,2,7,23} {1,1 ..., 1,1,2,7,23}
{1,1 .. ., 1,1,2,8,20} {1,1 ..., 1,1,2,8,20}
{1,1 ..., 1,1,3,3,37} {1 , 1 ..., 1,1,3,3,37}
{1,1 ..., 1,1,3,4,27} {1,1 ..., 1,1,3,4, 27}
{1,1 ..., 1,1,3,7,15} {1,1 ..., 1,1,3,7,15}
{1,1 ..., 1,2, 2,6,13} {1,1 ..., 1,2,2,6,13}

J42161217
la source
1
"Si votre réponse [...] est écrite dans une langue que je ne peux pas tester avec un logiciel disponible gratuitement, je ne noterai pas votre réponse."
Leaky Nun
4
@GB "vous êtes autorisé à publier des réponses qui génèrent des solutions incomplètes"
user202729
1
mon programme "..génère le plus de combinaisons pour le n le plus élevé en une minute" .Il n'est pas codé en dur.Il trouve juste les 12 premières solutions "les plus faciles" en moins d'une minute
J42161217
1
Il pourrait être plus clair que n était censé être une entrée. Je l'ai clarifié maintenant. Il ne semble pas que votre programme prenne une entrée n .
orlp
2
@orlp Fixed! Mon programme prend n'importe quel n comme entrée. Pour n = 293, vous obtenez les 12 solutions. un-downvote s'il vous plaît si puisque tout fonctionne!
J42161217
2

Python 2 , n = 175, 28 résultats en 59s

Rendu un peu plus lent en utilisant un facteur de réduction 2, mais obtient plus de solutions à partir de n = 83

J'obtiens des résultats pour n jusqu'à 92 sur TIO en une seule fois.

def submats(n, r):
    if n == r:
        return [[]]
    elif r > 6:
        base = 1
    else:
        base = 2
    mx = max(base, int(n*2**(1-r)))

    mats = []
    subs = submats(n, r+1)
    for m in subs:
        if m:
            mn = m[-1]
        else:
            mn = 1
        for i in range(mn, mx + 1):
            if i * mn < 3*n:
                mats += [m + [i]]
    return mats

def mats(n):
    subs = []
    for sub in submats(n, 0):
        sum = 0
        prod = 1
        for m in sub:
            sum += m
            prod *= m
        if prod > n and prod < n*3:
            subs += [[sub, sum, prod]]
    return subs

def sols(n):
    mat = mats(n)
    sol = [
        [[1]*(n-1)+[3*n-1],[1]*(n-2)+[2,2*n-1]],
    ]
    if n > 2:
        sol += [[[1]*(n-1)+[2*n+1],[1]*(n-2)+[3,n]]]
    for first in mat:
        for second in mat:
            if first[2] == second[1] and first[1] == second[2] and [second[0], first[0]] not in sol:
                sol += [[first[0], second[0]]];
    return sol

Essayez-le en ligne!

GB
la source
1
"garder 5 éléments [1..2] et limiter 3n ..." Je suis content que vous ayez aimé mon algorithme ;-)
J42161217
J'ai déjà fait quelque chose de similaire dans la version Ruby, et maintenant j'essaie de supprimer cette limitation.
GB
Pour un n donné, combien de solutions sont codées en dur dans votre algorithme?
J42161217
Pas vraiment codé en dur: 2 solutions standard peuvent être générées à l'aide d'un raccourci (sauf pour n = 2 où elles sont la même combinaison), et en les sautant, je peux limiter la plage à 2n au lieu de 3n. Si cela est considéré comme codé en dur, je vais le changer.
GB
1
Pour 61 mon résultat serait 28 votre je me souviens que c'est 27 ... Peut-être que j'ai fait une erreur
RosLuP
1

Ruby , n = 12 obtient 6 solutions

Au moins sur TIO, résultats habituels de 1 à 11

->n{
  arr=[*1..n*3].product(*(0..n-2).map{|x|
    [*1..[n/3**x,2].max]|[1]
  }).select{|a|
    a.count(1) >= n-4
  }.map(&:sort).uniq
  arr.product(arr).map(&:sort).uniq.select{|r|
    r[0].reduce(&:+) == r[1].reduce(&:*) &&
    r[0].reduce(&:*) == r[1].reduce(&:+)
  }
}

Essayez-le en ligne!

Obtient 10 résultats en moins d'une minute pour n = 13 sur mon ordinateur portable.

GB
la source
1

Mathematica, n = 19 avec 11 solutions

c'est ma nouvelle réponse selon les nouveaux critères d'OP

(SOL = {};
For[a = 1, a < 3, a++, 
For[b = a, b < 3, b++, 
For[c = b, c < 5, c++, 
 For[d = c, d < 6, d++, 
  For[e = d, e < 3#, e++, 
   For[k = 1, k < 3, k++, 
    For[l = k, l < 3, l++, 
     For[m = l, m < 5, m++, 
      For[n = m, n < 6, n++, For[o = n, o < 3#, o++,
        s = Join[Table[1, # - 5], {a, b, c, d, e}];
        t = Join[Table[1, # - 5], {k, l, m, n, o}];            
        If[Tr[s[[-# ;;]]] == Times @@ t[[-# ;;]] && 
          Tr[t[[-# ;;]]] == Times @@ s[[-# ;;]], 
         AppendTo[SOL,{s[[-#;;]],t[[-#;;]]}]]]]]]]]]]]];
Union[SortBy[#,Last]&/@SOL])&

si vous donnez une entrée [n] à la fin, le programme affiche les solutions

voici mes résultats (sur mon ancien portable 64 bits 2,4 GHz)

n-> solutions
2 -> 2
3 -> 4
4 -> 3
5 -> 5
6 -> 4
7 -> 6
8 -> 5
9 -> 7
10 -> 7
11 -> 8
12 -> 6 (en 17 s)
13 -> 10 (en 20 s)
14 -> 7 (en 25 s)
15 -> 7 (en 29 s)
16 -> 9 (en 34 s)
17 -> 10 (en 39 s)
18 - > 9 (en 45 sec)
19 -> 11 (en 51 sec)
20 -> 7 (en 58 sec)

J42161217
la source
1

Haskell, beaucoup de solutions rapidement

import System.Environment

pr n v = prh n v v

prh 1 v l = [ [v] | v<=l ]
prh n 1 _ = [ take n $ repeat 1 ]
prh _ _ 1 = []
prh n v l = [ d:r | d <-[2..l], v `mod` d == 0, r <- prh (n-1) (v`div`d) d ]

wo n v = [ (c,k) | c <- pr n v, let s = sum c, s>=v,
                   k <- pr n s, sum k == v, s>v || c>=k ]

f n = concatMap (wo n) [n+1..3*n]

main = do [ inp ] <- getArgs
          let results = zip [1..] $ f (read inp)
          mapM_ (\(n,s) -> putStrLn $ (show n) ++ ": " ++ (show s)) results

fcalcule les solutions, la mainfonction ajoute l'obtention de l'entrée à partir de la ligne de commande et un certain formatage et comptage.

Christian Sievers
la source
Compilez comme ceci: ghc -O3 -o prodsum prodsum.hset exécutez avec l'argument de ligne de commande:./prodsum 6
Christian Sievers
0

Haskell , n = 10 avec 2 solutions


import           Data.List

removeDups = foldl' (\seen x -> if x `elem` seen then seen else x : seen) []
removeDups' = foldl' (\seen x -> if x `elem` seen then seen else x : seen) []

f n= removeDups $ map sort filterSums
  where maxNumber = 4
        func x y = if (((fst x) == (fst.snd$y)) && ((fst y) == (fst.snd$x)))
                     then [(snd.snd$x),(snd.snd$y)]
                     else [[],[]]
        pOf = removeDups' $ (map sort (mapM (const [1..maxNumber]) [1..n]))
        sumOf = map (\x->((sum x),((product x), x))) pOf
        filterSums = filter (\x-> not$(x == [[],[]])) (funcsumOfsumOf)

Cela fonctionne comme de la merde, mais je l'ai au moins corrigé, donc je relève le défi maintenant!

Essayez-le en ligne!

maple_shaft
la source
pour n = 2, vous obtenez ["[3,3] [2,3]", "[2,2] [2,2]", "[1,3] [2,2]", "[1, 2] [1,3] "," [1,1] [1,2] "], ce qui est faux
J42161217
Toutes les solutions semblent être en fait erronées
GB
@Jenny_mathy Comment est-ce mal? 3 + 3 est 6 et 2 * 3 est 6. Dois-je mal comprendre la question.
maple_shaft
il vous manque le "vice versa"
J42161217
@Jenny_mathy Erreur stupide de ma part! Je l'ai corrigé, devrait fonctionner maintenant.
maple_shaft
0

Axiome, n = 83 en 59 secondes ici

-- copy the below text in the file name "thisfile.input" 
-- and give something as the command below in the Axiom window:
-- )read C:\Users\thisuser\thisdirectory\thisfile

)cl all
)time on

-- controlla che l'array a e' formato da elementi  a.i<=a.(i+1)
tv(a:List PI):Boolean==(for i in 1..#a-1 repeat if a.i> a.(i+1) then return false;true)

-- funzione incremento: incrementa a, con #a=n=b/3,sotto la regola di "reduce(+,a)+#a-1>=reduce(*,a)"
-- e che n<reduce(*,a)<3*n ed reduce(+,a)<3*n 
inc3(a:List PI):INT==
   i:=1; n:=#a; b:=3*n
   repeat
      if i>n  then return 0
      x:=reduce(*,a)
      if x>=b then a.i:=1
      else
          y:=reduce(+,a)
          if y>b then a.i=1
          else if y+n-1>=x then
                      x:=x quo a.i
                      a.i:=a.i+1
                      x:=x*a.i
                      if tv(a) then break
                      else a.i:=1
          else a.i:=1
      i:=i+1
   if x<=n then return inc3(a) -- x<=n non va
   x

-- ritorna una lista di liste di 4 divisori di n
-- tali che il loro prodotto e' n
g4(n:PI):List List PI==
  a:=divisors(n)
  r:List List PI:=[]
  for i in 1..#a repeat
     for j in i..#a repeat
        x:=a.i*a.j
        if x*a.j>n then break
        for k in j..#a repeat
            y:=x*a.k
            if y*a.k>n then break
            for h in k..#a repeat
                z:=y*a.h
                if z=n  then r:=cons([a.h,a.k,a.j,a.i],r)
                if z>=n then break 
  r

-- ritorna una lista di liste di 3 divisori di n
-- tali che il loro prodotto e' n
g(n:PI):List List PI==
  a:=divisors(n)
  r:List List PI:=[]
  for i in 1..#a repeat
     for j in i..#a repeat
        x:=a.i*a.j
        if x*a.j>n then break
        for k in j..#a repeat
            y:=x*a.k
            if y=n  then r:=cons([a.k,a.j,a.i],r)
            if y>=n then break
  r

-- cerca che [a,b] nn si trovi gia' in r
searchr(r:List List List PI,a:List PI,b:List PI):Boolean==
  aa:=sort(a); bb:=sort(b)
  for i in 1..#r repeat
      x:=sort(r.i.1);y:=sort(r.i.2)
      if x=aa and y=bb then return false
      if x=bb and y=aa then return false
  true

-- input n:PI
-- ritorna r, tale che se [a,b] in r
-- allora #a=#b=n
--        ed reduce(+,a)=reduce(*,b) ed reduce(+,b)=reduce(*,a)
f(n:PI):List List List PI==
  n>100000 or n<=1 =>[]
  a:List PI:=[]; b:List PI:=[]; r:List List List PI:=[]
  for i in 1..n repeat(a:=cons(1,a);b:=cons(1,b))
  if n~=72 and n<86 then  m:=min(3,n)
  else                    m:=min(4,n) 
  q:=reduce(*,a) 
  repeat
    w:=reduce(+,a)
    if n~=72 and n<86 then x:= g(w)
    else                   x:=g4(w)
    if q=w then r:=cons([copy a, copy a],r)
    for i in 1..#x repeat
           for j in 1..m repeat
                  b.j:=(x.i).j
           -- per costruzione abbiamo che reduce(+,a)= prodotto dei b.i=reduce(*,b)
           -- manca solo di controllare che reduce(+,b)=reduce(*,a)=q
           if reduce(+,b)=q and searchr(r,a,b) then r:=cons([copy a, copy b],r)
    q:=inc3(a)
    if q=0 then break
  r

résultats:

 for i in 2..83 repeat output [i, # f(i)]
   [2,2][3,4][4,3][5,5][6,4][7,6][8,5][9,7][10,7][11,8][12,6][13,10][14,7][15,7]
   [16,10][17,10][18,9][19,12][20,7][21,13][22,9][23,14][24,7][25,13][26,11]
   [27,10][28,11][29,15][30,9][31,16][32,11][33,17][34,9][35,9][36,13][37,19]
   [38,11][39,14][40,12][41,17][42,11][43,20][44,12][45,16][46,14][47,14][48,13]
   [49,16][50,14][51,17][52,11][53,20][54,15][55,17]
   [56,14][57,20][58,17][59,16][60,15][61,28][62,15][63,16][64,17][65,18]
   [66,14][67,23][68,20][69,19][70,13][71,18][72,15][73,30][74,15][75,17][76,18]
   [77,25][78,16][79,27][80,9][81,23][82,17][83,26]


 f 3
    [[[1,2,5],[8,1,1]],[[1,3,3],[7,1,1]],[[1,2,3],[1,2,3]],[[2,2,2],[6,1,1]]]
                                     Type: List List List PositiveInteger
                                   Time: 0.07 (IN) + 0.05 (OT) = 0.12 sec

La façon d'exécuter le texte au-dessus d'Axiom serait de copier tout ce texte dans un fichier, d'enregistrer le fichier sous le nom: Name.input, dans une fenêtre Axiom, utilisez ") read absolutepath / Name".
résultats: (# f (i) trouve la longueur du tableau f (i), c'est-à-dire le nombre de solutions)

RosLuP
la source