Encuentra el binarray!

24

Definimos un binarray como una matriz que satisface las siguientes propiedades:

  • no está vacío
  • el primer valor es un 1
  • el último valor es un 1
  • todos los demás valores son 0o1

Por ejemplo, la matriz [ 1, 1, 0, 1 ]es una matriz binaria válida .

La tarea

Dada una matriz no vacía A de enteros no negativos y un entero positivo N , su trabajo es encontrar una matriz binaria B de longitud N que permita generar A al sumar un número ilimitado de copias de B , desplazado por un número ilimitado de puestos.

Ejemplo

A = [ 1, 1, 2, 4, 1, 2, 2, 1, 0, 1, 0, 1, 1, 0, 1 ]
N = 4

Para esta entrada, el binarray B = [ 1, 1, 0, 1 ] sería una respuesta válida porque podemos hacer:

  [ 1, 1, 0, 1 ]
+       [ 1, 1, 0, 1 ]
+       [ 1, 1, 0, 1 ]
+          [ 1, 1, 0, 1 ]
+                   [ 1, 1, 0, 1 ]
+                                  [ 1, 1, 0, 1 ]
  -----------------------------------------------
= [ 1, 1, 2, 4, 1, 2, 2, 1, 0, 1, 0, 1, 1, 0, 1 ]

Reglas

  • La entrada puede tomarse en cualquier formato razonable.
  • La salida puede ser una matriz nativa (por ejemplo [1, 1, 0, 1]) o una cadena binaria con o sin separador (por ejemplo, "1,1,0,1"o "1101")
  • Solo debe imprimir o devolver un binarray válido . Alternativamente, usted puede optar por imprimir o devolver todos ellos cuando existen varias soluciones.
  • No está obligado a admitir entradas que no conducen a ninguna solución.
  • La suma puede incluir ceros implícitos que no se solapan con cualquier copia de B . El segundo cero en la suma anterior es un cero implícito.
  • Puede suponer que el tamaño máximo de A es 100 y el tamaño máximo de B es 30.
  • Este es el código de golf, por lo que gana la respuesta más corta en bytes. Las lagunas estándar están prohibidas.

Casos de prueba

Input : N = 1 / A = [ 1, 2, 3, 4, 5 ]
Output: [ 1 ]

Input : N = 2 / A = [ 1, 2, 100, 99 ]
Output: [ 1, 1 ]

Input : N = 3 / A = [ 1, 1, 1 ]
Output: [ 1, 1, 1 ]

Input : N = 3 / A = [ 1, 1, 3, 2, 2 ]
Output: [ 1, 1, 1 ]

Input : N = 3 / A = [ 1, 0, 2, 1, 1, 1, 0, 0, 1, 0, 1 ]
Output: [ 1, 0, 1 ]

Input : N = 4 / A = [ 1, 2, 2, 2, 1 ]
Output: [ 1, 1, 1, 1 ]

Input : N = 4 / A = [ 1, 1, 2, 4, 1, 2, 2, 1, 0, 1, 0, 1, 1, 0, 1 ]
Output: [ 1, 1, 0, 1 ]

Input : N = 4 / A = [ 1, 1, 0, 2, 1, 0, 1 ]
Output: [ 1, 0, 0, 1 ] or [ 1, 1, 0, 1 ]

Input : N = 5 / A = [ 1, 3, 6, 9, 8, 6, 3, 4 ]
Output: [ 1, 1, 1, 0, 1 ]

Input : N = 8 / A = [ 2, 1, 0, 2, 3, 3, 1, 2, 1 ]
Output: [ 1, 0, 0, 1, 1, 1, 0, 1 ]

Input : N = 10 / A = [ 1, 2, 1, 2, 2, 1, 3, 3, 3, 2, 3, 0, 2, 1, 1, 0, 1 ]
Output: [ 1, 1, 0, 1, 0, 1, 1, 1, 0, 1 ]

Input : N = 13 / A = [ 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1 ]
Output: [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 ]

Input : N = 5 / A = [ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 ]
Output: [ 1, 1, 1, 1, 1 ]

Input : N = 6 / A = [ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 ]
Output: [ 1, 0, 0, 0, 0, 1 ]

Input : N = 7 / A = [ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 ]
Output: [ 1, 1, 0, 0, 0, 1, 1 ]

Input : N = 9 / A = [ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 ]
Output: [ 1, 0, 1, 0, 1, 0, 1, 0, 1 ]
Arnauld
fuente
¿Cuál es el valor más grande de Neso razonablemente debe ser compatible?
Neil
@Neil He agregado límites de tamaño tanto en A como en B.
Arnauld
1
@ fəˈnɛtɪk Quizás, pero para N=4, A = [ 1, 1, 2, 4, 1, 2, 2, 2, 1, 2, 2, 1, 2, 0, 1 ], obtienes 30459 que es divisible por 11 y 13 pero solo uno de [ 1, 1, 0, 1 ]y [ 1, 0, 1, 1 ]es una respuesta válida.
Neil
1
@ fəˈnɛtɪk Estos números no están escritos en la base 2, por lo que no se aplican las reglas de la aritmética. Por ejemplo, explícitamente no puede llevar al agregar.
BallpointBen
2
Agregue estos casos de prueba, que parecen romper casi todas las respuestas publicadas: N = 3, A = [1, 0, 2, 0, 2, 0, 1], salida = [1, 0, 1]; N = 3, A = [1, 1, 1, 0, 0, 0, 1, 1, 1], salida = [1, 1, 1].
Anders Kaseorg

Respuestas:

8

PHP, 105 92 90 86 bytes

La solución de Jörg fija y golfizada:

for($b=1+2**$argv[1];;)--$argc>1?$s+=$argv[$argc]*2**$i++:$s%($b-=2)||die(decbin($b));

toma Ndel primer argumento de la línea de comando, valores después de eso; ejecutarlo -ro probarlo en línea .
imprime número binario (formato 10001); imprime una solución no válida o se agota si no hay una solución válida.

primera versión (ahora 97 bytes) que no imprime nada para entradas no válidas: pruébelo en línea

for($b=1+$m=2**$argv[1];$m/2<=$b;)--$argc>1?$s+=$argv[$argc]*2**$i++:$s%($b-=2)||die(decbin($b));

Descompostura

for($b=1+$m=2**$argv[1];$m/2<=$b;)  # second loop: loop $b from 2^N-1 by -2 to 2^(N-1)
--$argc>1                           # first loop: decrease $argc ...
    ?$s+=$argv[$argc]*2**$i++           # while $argc>1: binary sum from last to 2nd argument
    :$s%($b-=2)||die(decbin($b));       # later: if $b divides $s, print in binary and exit
Titus
fuente
Niza, ¿no podrías alcanzar un conteo de bytes por debajo de 100?
Jörg Hülsermann
1
@ JörgHülsermann pude.
Titus
Pensamiento pesado. Sé antes de esto que eres mejor. Espero que pueda mantener el conteo de bytes más bajo
Jörg Hülsermann
1
En N = 3, A = [1, 0, 2, 0, 2, 0, 1], esto devuelve incorrectamente111 donde el único resultado correcto es [1, 0, 1].
Anders Kaseorg
8

PHP , 219 bytes

<?for(list($g,$z)=$_GET,$d=~-$l=2**$z;$d>=$l/2;max(array_diff_assoc($r,$g)?:[0])?:$o[]=$b,$d-=2)for($r=[],$b=decbin($d),$k=0;$k<count($g);$k++)for($u=$g[$k]-$r[$k],$i=0;$i<$z;$i++)$u<1?:$r[$k+$i]+=$u*$b[$i];print_r($o);

Pruébalo en línea!

-4 Bytes usando [$g,$z]=$_GETPHP 7.1 en lugar delist($g,$z)=$_GET

Jörg Hülsermann
fuente
Parece que genera una [1,0,1,0,1,0,1,0,1]respuesta válida ( ) y una respuesta no válida ( [1,0,0,0,1,0,1,1,1]) para el último caso de prueba.
Arnauld
-8 Bytes: while($_GET[0])$s+=2**$i++*array_pop($_GET[0]);. -5 Bytes: range(1|.5*$m=2**$_GET[1],$m,2).
Titus
@Arnauld Sí, debería dar como Salida solo el binarray más alto para que esta solución sea válida
Jörg Hülsermann
2
@ fəˈnɛtɪk Estoy de acuerdo con sus cálculos, pero el desafío consiste en encontrar un patrón que se pueda sumar exactamente a A, no un arreglo equivalente. Aquí, llegaríamos [ 1,0,1,1,1,0,2,2,2,2,2,1 ].
Arnauld
1
-1 byte con for($g=$_GET[0];$g;).
Titus
3

Python, 166 bytes

def f(a,n):
 for i in range(1<<n-1,1<<n):
  b=bin(i)[2:];u,v=(int(('0{:0>%d}'%sum(a)*len(s)).format(*s))for s in[a,b])
  if u%v<1>int(str(u//v*10)[::~sum(a)]):yield b

Pruébalo en línea!

Cómo funciona

Considere A y B como los dígitos de los números base k u y v . Por ejemplo (usaremos k = 1000 como ilustración):

A = [1, 2, 1, 3, 2, 1, 2]
B = [1, 0, 0, 1]
u = 1 002 001 003 002 001 002
v = 1 000 000 001

Como muchos de los otros respondedores notaron, si B es una respuesta válida, entonces u es divisible por v . En este caso,

u = 1 002 001 002 ⋅ v

Este cociente, traducido de nuevo a la matriz [1, 2, 1, 2], nos dice exactamente cuántas copias de B necesitamos desplazar a cada posición.

  [1, 0, 0, 1]
+    [1, 0, 0, 1]
+    [1, 0, 0, 1]
+       [1, 0, 0, 1]
+          [1, 0, 0, 1]
+          [1, 0, 0, 1]
-----------------------
  [1, 2, 1, 3, 2, 1, 2]

(¿Por qué? Porque eso es exactamente cuánto tiempo funciona la multiplicación en base k .)

Lo que los otros respondedores no notaron es que la condición anterior no es suficiente . Por ejemplo:

A = [1, 2, 1, 3, 2, 1, 2]
B = [1, 1, 1, 1]
u = 1 002 001 003 002 001 002
v = 1 001 001 001
u = 1 000 999 002 ⋅ v

Hablando matemáticamente, aún podemos traducir ese cociente de nuevo a la matriz [1, 1, −1, 2], que funciona bien si se nos permite usar copias negativas de B:

  [1, 1, 1, 1]
+    [1, 1, 1, 1]
       [1, 1, 1, 1]
+          [1, 1, 1, 1]
+          [1, 1, 1, 1]
-----------------------
  [1, 2, 1, 3, 2, 1, 2]

pero, por supuesto, el desafío no permite copias negativas. Entonces necesitamos un cheque adicional.

Con ese fin, seleccionamos una base k = 10 e donde k > 10 ⋅ suma (A), y verificamos que ninguno de los dígitos k base se desborde en el siguiente dígito k base cuando multiplicamos el cociente por diez. Es decir, cada e º dígitos diez base, comenzando en el extremo, en la representación de diez base de la veces cociente diez, debe ser 0. Esto garantiza que el cociente se traduce de nuevo a una matriz con elementos no negativos.

Anders Kaseorg
fuente
1
Me encanta tu truco de usar una gran potencia de 10 como base para facilitar la conversión de la base.
Neil
2

PHP, 213 bytes

De la misma manera un poco golfizado

<?for($b=2**~-$l=$_GET[1];$b<2**$l;array_filter($t[$b++])?:$d[]=$o)for($g=count($t[$b]=$_GET[$i=0]);min($t[$b])>-1&$i<=$g-$l;$i++)for($e=$t[$b][$i],$k=0,$o=decbin($b);$k<$l;)$t[$b][$k+$i]-=$o[$k++]*$e;print_r($d);

Pruébalo en línea!

PHP, 344 Bytes primero trabajando

Después de mi primera respuesta, he decidido hacer un intento más largo para devolver todas las soluciones válidas.

<?foreach(range(2**($l=$_GET[1])-1,2**($l-1))as$b){$t[$b]=($g=$_GET[0]);for($i=0;$t[$b]&&$i<=count($g)-$l;$i++){$e=reset($y=array_slice($t[$b],$i,$l));foreach(str_split(decbin($b))as$k=>$v)$t[$b][$k+$i]=$y[$k]-$e*$v;if(min($t[$b])<0)unset($t[$b]);}}foreach($t as$k=>$v)if(max($v)>0)unset($t[$k]);echo join(",",array_map(decbin,array_keys($t)));

Versión en línea

Descompostura

foreach(
    range(2**($l=$_GET[1])-1
    ,2**($l-1)
    ) # make decimal range of a binarray with given length
    as$b){
$t[$b]=($g=$_GET[0]); # make a copy for each possible solution pattern
    for($i=0;$t[$b]&&$i<=count($g)-$l;$i++){ # Loop till solution is valid or reach last digit
        $e=reset($y=array_slice($t[$b],$i,$l)); # take first value of a sequence with the length
        foreach(str_split(decbin($b))as$k=>$v)
            $t[$b][$k+$i]=$y[$k]-$e*$v; # replace values in copy
        if(min($t[$b])<0)unset($t[$b]); # kill solution if a minimum <0 exists
    }
}
foreach($t as$k=>$v)if(max($v)>0)unset($t[$k]); # drop all solutions where the sum is not zero 


echo join(",",array_map(decbin,array_keys($t))); #Output all solutions
Jörg Hülsermann
fuente
Esto parece funcionar para N ≥ 2, pero falla en N = 1 casos, como el primer caso de prueba en el desafío.
Anders Kaseorg
@AndersKaseorg Ahora es compatible con los N = 1 Casos que solo necesita establecer =en el primer bucle para la versión más corta En la versión más grande necesita eliminar cuatro Bytes
Jörg Hülsermann
1

Python, 205 bytes

def f(a,l):
 b=lambda s:b(s[:-1])*sum(a)*8+int(s[-1])if s else 0
 c=lambda n:n and(n/sum(a)/4%2 or c(n/sum(a)/8))
 for i in range(2**~-l,2**l):
  j=bin(i)[2:]
  if b(a)%b(j)<1 and not c(b(a)/b(j)):return j

Devuelve una cadena binaria sin separador. Como @AndersKaseorg señala, hay entradas para las cuales la solución de @ fəˈnɛtɪk no funciona porque la división representa un coeficiente negativo que no está permitido. Para evitar esto, utilizo una base muy grande y pruebo que no hay préstamos en la división.

Neil
fuente
De acuerdo, creo que este es un contraejemplo real: f([1, 1, 1, 0, 0, 0, 1, 1, 1], 3)devuelve incorrectamente 101.
Anders Kaseorg
@AndersKaseorg Hmm, ¿revertir el orden del bucle ayuda, o el algoritmo todavía está fundamentalmente roto?
Neil
Creo que está fundamentalmente roto sin controles adicionales. La variante inversa falla f([1, 0, 2, 0, 2, 0, 1], 3)y las variantes directa e inversa fallan f([1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0], 5).
Anders Kaseorg
E incluso si comprueba que ies extraño, tanto las variantes hacia adelante como hacia atrás fallan f([1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0]*10, 5).
Anders Kaseorg
1
@AndersKaseorg Ah sí, cuando gcd (k, n) = 1, (x^kn-1)/(x^k-1)siempre tiene (x^n-1)/(x-1)como factor, lo que engaña a la solución de @ fəˈnɛtɪk en cualquier base.
Neil
1

Pyth, 32 bytes

f!|%FKiRJysQ,QT>#sQj/FKJ+L1^U2tE

Pruébalo en línea

Cómo funciona

                           ^U2tE   Cartesian power [0, 1]^(N - 1)
                        +L1        prepend 1 to every list
f                                  filter for lists T such that:
          sQ                         sum(A)
         y                           double
        J                            assign to J
      iR    ,QT                      convert [A, T] from base J
     K                               assign to K
   %F                                fold modulo
  |                                  logical OR with
                    /FK                fold integer division over K
                   j   J               convert to base J
               >#sQ                    filter for digits greater than sum(A)
 !                                   logical NOT

La estrategia es similar a mi respuesta de Python , excepto que debido a que Pyth tiene funciones integradas para la conversión de bases, podemos usar una base más eficiente k = 2 ⋅ sum (A), y verificar directamente que cada dígito del cociente sea como máximo sum (A )

Anders Kaseorg
fuente
1

Pari / GP , 77 74 96 80 bytes

n->a->[v|d<-divisors(b=Pol(a)),(v=Vec(d))%2==v&&vecmin(Vec(b/d))>=0&&d%x&&#d==n]

Devuelve todas las soluciones.

Primero convierte la matriz aen un polinomio b. Luego elige de los divisores blos polinomios de dmodo que los coeficientes de dson todos 1y 0, y los coeficientes de b / dtodos son no negativos, y d(0) = 1, y deg(d) = n + 1. Finalmente, los convierte nuevamente en matrices.

Pruébalo en línea!

alephalpha
fuente