Encuentra todos los pares de números que suman 121212 [cerrado]

8

Este problema es bastante fácil de hacer por fuerza bruta. De hecho, será razonablemente rápido para la fuerza bruta también. ¿Pero dónde está la diversión en eso?

El problema

Produzca una lista de todos los pares de números de 5 dígitos únicos que sumen 121212. Sin embargo, cada dígito decimal debe aparecer exactamente una vez en cualquier número. Entonces sería un par válido (98167, 23045). Pero un par no válido se debe a (23456, 97756)que 7, 5, 6se repiten más de una vez y 1, 8, 0no se utilizan en absoluto. Hay exactamente 192 pares únicos.

Reglas

  1. Eficiencia: puedes forzarlo con fuerza bruta. Pero eso es trivial de hacer. Entonces, en cambio, el verdadero desafío aquí es encontrar una manera de producir eficientemente la lista de números.

  2. Requisitos del código fuente: no puede almacenar la lista de números (ni ninguna parte de ella). La secuencia numérica se debe generar sobre la marcha.

¡Que te diviertas!

ircmaxell
fuente
1
¿Me perdí la parte donde dijiste "Asumir base 10"? ;)
kojiro
1
@kojiro: ¿Cuántos dedos tienes? :-)
mellamokb
1
@kojiro: No. Si puedes encontrar otras bases donde funciona, por supuesto ... ¡Creo que sería increíble!
ircmaxell
@kojiro tipo de: " cada dígito decimal debe aparecer ... " aunque parece que podría encontrar dos números hexadecimales de 5 dígitos siempre que no contengan AF
Cefalópodo
@mellamokb 10 dedos, pero tengo 20 dígitos.
kojiro

Respuestas:

6

JavaScript

function findpairs(arrin1,arrin2){
    functioncount++
    var arr1=[]
    var arr2=[]
    var strike=[]
    var overflow=0
    var b
    var len=arrin1.length
    for(var a=0;a<len;a++){
        arr1[a]=arrin1[a]
        arr2[a]=arrin2[a]
        strike[arr1[a]]=true
        strike[arr2[a]]=true
        overflow=+((arr1[a]+arr2[a])>9)
    }
    var desired=12-(len%2)-overflow
    for(a=9;a>0;a--){
        b=(desired-a)%10
        if(a>b && !strike[a] && !strike[b]){
            if(len==4){
                if((a+b)>9){
                    document.write(""+a+arr1[3]+arr1[2]+arr1[1]+arr1[0]+" "+b+arr2[3]+arr2[2]+arr2[1]+arr2[0]+"<br>")
                    document.write(""+a+arr1[3]+arr1[2]+arr1[1]+arr2[0]+" "+b+arr2[3]+arr2[2]+arr2[1]+arr1[0]+"<br>")
                    document.write(""+a+arr1[3]+arr1[2]+arr2[1]+arr1[0]+" "+b+arr2[3]+arr2[2]+arr1[1]+arr2[0]+"<br>")
                    document.write(""+a+arr1[3]+arr1[2]+arr2[1]+arr2[0]+" "+b+arr2[3]+arr2[2]+arr1[1]+arr1[0]+"<br>")
                    document.write(""+a+arr1[3]+arr2[2]+arr1[1]+arr1[0]+" "+b+arr2[3]+arr1[2]+arr2[1]+arr2[0]+"<br>")
                    document.write(""+a+arr1[3]+arr2[2]+arr1[1]+arr2[0]+" "+b+arr2[3]+arr1[2]+arr2[1]+arr1[0]+"<br>")
                    document.write(""+a+arr1[3]+arr2[2]+arr2[1]+arr1[0]+" "+b+arr2[3]+arr1[2]+arr1[1]+arr2[0]+"<br>")
                    document.write(""+a+arr1[3]+arr2[2]+arr2[1]+arr2[0]+" "+b+arr2[3]+arr1[2]+arr1[1]+arr1[0]+"<br>")
                    document.write(""+a+arr2[3]+arr1[2]+arr1[1]+arr1[0]+" "+b+arr1[3]+arr2[2]+arr2[1]+arr2[0]+"<br>")
                    document.write(""+a+arr2[3]+arr1[2]+arr1[1]+arr2[0]+" "+b+arr1[3]+arr2[2]+arr2[1]+arr1[0]+"<br>")
                    document.write(""+a+arr2[3]+arr1[2]+arr2[1]+arr1[0]+" "+b+arr1[3]+arr2[2]+arr1[1]+arr2[0]+"<br>")
                    document.write(""+a+arr2[3]+arr1[2]+arr2[1]+arr2[0]+" "+b+arr1[3]+arr2[2]+arr1[1]+arr1[0]+"<br>")
                    document.write(""+a+arr2[3]+arr2[2]+arr1[1]+arr1[0]+" "+b+arr1[3]+arr1[2]+arr2[1]+arr2[0]+"<br>")
                    document.write(""+a+arr2[3]+arr2[2]+arr1[1]+arr2[0]+" "+b+arr1[3]+arr1[2]+arr2[1]+arr1[0]+"<br>")
                    document.write(""+a+arr2[3]+arr2[2]+arr2[1]+arr1[0]+" "+b+arr1[3]+arr1[2]+arr1[1]+arr2[0]+"<br>")
                    document.write(""+a+arr2[3]+arr2[2]+arr2[1]+arr2[0]+" "+b+arr1[3]+arr1[2]+arr1[1]+arr1[0]+"<br>")
                    resultcount+=16
                }
            }
            else{
                arr1[len]=a
                arr2[len]=b
                findpairs(arr1,arr2)
            }
        }
    }
}
resultcount=0
functioncount=0
start=+new Date()
findpairs([],[])
end=+new Date()
document.write("<br>"+resultcount+" results<br>"+(end-start)+" ms<br>"+functioncount+" function calls")

Alojado en: http://ebusiness.hopto.org/findpairs.htm

Realización matemática: si tiene un par, se pueden generar otros 15 trivialmente intercambiando dígitos entre los dos números, por lo tanto, solo busco números en los que los dígitos del primero sean todos mayores que los dígitos del segundo, y luego simplemente genere todos los permutaciones

Comienzo desde los dígitos menos significativos y genero la secuencia como un recorrido de árbol, para cada paso afirmando que el resultado intermedio es correcto y que no se gastan dígitos dos veces. Con estos métodos, la función solo necesita llamarse 50 veces en total. En mi máquina, Chrome produce resultados de tiempo de ejecución de 2 ms.

aaaaaaaaaaaa
fuente
8

C ++

#include<iostream>
using namespace std;
#include<algorithm>

int main()
{
    long long N,F,S;
    char str[11]="1023456789";
    while (1) {
        sscanf(str,"%lld",&N);
        F=N/100000;S=N%100000;
        if (F>60000)
           break;
        if (F+S==121212)
           printf("%lld %lld\n",F,S);
        next_permutation(str,str+10);
    }
}

http://www.ideone.com/Lr84g

fR0DDY
fuente
2
Muy interesante. Entonces, está iterando sobre todas las permutaciones posibles donde la parte superior es inferior a 60001 (aproximadamente 1,768,168 iteraciones, o un poco menos 10!/2) y luego verifica si es sumable a 121212. No está nada mal para una primera ejecución. Pero todavía tengo curiosidad si podemos ser más eficientes ...
ircmaxell
Hmmm, pensé que no podías almacenar la lista de números ... ¿Fraseología ambigua?
bltxd
@bltxd: quise decir almacenarlo de antemano. Puede almacenarlo a medida que lo genera. Pero no puede almacenar que (51430, 69872)es un par válido. Puede almacenar previamente la lista de dígitos ( 0123456789) y la suma ( 121212).
ircmaxell
Estoy de acuerdo en que no es la forma más eficiente de hacerlo, pero espero que sea diferente.
fR0DDY
4

Python 2.

Es bastante eficiente porque construye los números (el bucle más interno se ejecuta 4570 veces en total) y bastante corto porque jugué un poco (201 caracteres), pero no estoy realmente seguro de querer explicar esto :)

p=lambda t,a,d:((x,y)for x in range(10)for y in[(t-x-a)%10]if(x not in d)&(y not in d)and x-y)
w=lambda s:[s]if len(s)==10and s[:5]<s[5:]else(m for n in p(2-len(s)/2%2,sum(s[-2:])/10,s)for m in w(s+n))

Sin embargo, los valores devueltos son bastante peculiares: llame wcon una tupla vacía y obtendrá un iterador de 10 tuplas. Estas 10 tuplas son los dígitos de los dos números, por desgracia, al revés y alternativamente , es decir, la tupla

(2, 0, 8, 3, 7, 4, 9, 1, 6, 5)

representa los números 51430 y 69782.

Prueba:

result = list(w(()))

assert len(set(result)) == 192               # found all values
assert len(result) == 192                    # and no dupes 

for digits in result:
    assert all(0 <= d <= 9 for d in digits)  # real digits -- zero through nine
    assert len(set(digits)) == 10            # all digits distinct

    n1 = int("".join(map(str, digits[9::-2])))
    n2 = int("".join(map(str, digits[8::-2])))

    assert n1 + n2 == 121212                 # sum is correct

Aquí está la versión sin golf:

ppcalls = 0       # number of calls to possiblePairs
ppyields = 0      # number of pairs yielded by possiblePairs
ppconstructed = 0 # number of construced pairs; this is the number
                  #     of times we enter the innermost loop

def possiblePairs(theirSumMod10, addition, disallowed):
    global ppcalls, ppyields, ppconstructed
    ppcalls += 1
    for a in range(10):
        b = (theirSumMod10 - a - addition) % 10
        ppconstructed += 1
        if a not in disallowed and b not in disallowed and a != b:
            ppyields += 1
            yield (a, b)

def go(sofar):
    if len(sofar) == 10:
        if sofar[:5] < sofar[5:]: # dedupe
            yield sofar

    digitsum = 2 - (len(sofar) / 2) % 2 # 1 or 2, alternating

    for newpair in possiblePairs(digitsum, sum(sofar[-2:]) / 10, sofar):
        for more in go(sofar + newpair):
            yield more


list(go(()))        # iterate

print ppcalls       # 457
print ppyields      # 840
print ppconstructed # 4570
balpha
fuente
3

C

#include <stdio.h>

int mask(int n)
{
    int ret = 0;

    for (; n > 0; n /= 10)
        ret |= 1 << n % 10;

    return ret;
}

int main(void)
{
    int a, b;

    for (a = 21213, b = 99999; a < b; a++, b--)
        if ((mask(a) | mask(b)) == 0x3FF)
            printf("%d %d\n", a, b);

    return 0;
}

Esto atraviesa todos los pares de números de 5 dígitos que suman 121212 (es decir, 39393 iteraciones, o ~ 1/46 de las iteraciones utilizadas por la respuesta de fR0DDY ). Para cada par, forma una máscara de bits de los dígitos en cada número, luego ve si OR a 0b1111111111.

Joey Adams
fuente
Si agrega las 10 iteraciones para la máscara cada vez, deja la complejidad del tiempo solo ~ 1/5 veces mejor que la mía. :)
fR0DDY
2

Javascript (481)

function m(d,i){o=d-i;if(0<=o&&o<=9&&o!=i)return o;o+=10;if(0<=o&&o<=9&&o!=i)return o;return}function p(n,a){x=0;r=[];d=n%10;for(i=0;i<10;i++){if((!a||!a.contains(i))&&(o=m(d,i))&&(!a||!a.contains(o))&&i+o<=n)r[x++]=[i,o]}return r}function f(n,a){var x=0;var r=[];var d=p(n,a);for(var i=0;i<d.length;i++){var s=Math.floor((n-d[i][0]-d[i][1])/10);if(s>0){var t=f(s,d[i].concat(a));for(var j=0;j<t.length;j++)r[x++]=[t[j][0]*10+d[i][0],t[j][1]*10+d[i][1]]}else{r[x++]=d[i]}}return r}

http://jsfiddle.net/XAYr3/4/

Idea básica: generar combinaciones de dígitos válidos que se pueden usar en la columna de la derecha. Por ejemplo, (0,2), (3,9), (4,8), (5,7). Para cada combinación, encuentre recursivamente pares que funcionen para el siguiente dígito desde la derecha, sin duplicar dígitos en el primer par. Repetir hasta que se haya generado un par de números de 5 dígitos. Combine todos esos resultados en una sola matriz, y la lista es de 192 elementos. Creo que esto debería requerir la menor cantidad de iteraciones, pero toda la asignación / desasignación de matrices lo hace en general prácticamente ineficiente.

Mis pruebas de conteo muestran que la función fse llama 310 veces, el bucle interno ise ejecuta 501 veces en total (en todas las llamadas a f) y el bucle interno-interno jse ejecuta 768 veces en total (en todo).

mellamokb
fuente
1

Python, 171 caracteres

def R(x,y,d,c):
 if not d and x<y:print x,y
 for p in d:
  q=(12-c%2-p-(x+y)/10**c)%10
  if p-q and q in d:R(x+p*10**c,y+q*10**c,d-set([p,q]),c+1)
R(0,0,set(range(10)),0)

El código mantiene el invariante que x, ytienen cdígitos y que todos los dígitos no utilizados están en el conjunto d.

La rutina Rse llama un total de 841 veces, lo cual es bastante eficiente.

Keith Randall
fuente
0

C ++

#include<iostream>
using namespace std;
#include<algorithm>
#include<cstring>

int main()
{
        int i;
        char str1[11]="0123456789",str2[11];
        for (i=99999;i>60000;i--)
        {
                sprintf(str2,"%d%d",i,121212-i);
                sort(str2,str2+10);
                if(!strcmp(str1,str2))
                        printf("%d %d\n",i,121212-i);
        }
}

http://www.ideone.com/Lr84g

fR0DDY
fuente