Números de chocolate

17

Dada una mpor nbarra de chocolate, m,npositiva, la salida el número de formas de romper la barra en mn1 por 1 piezas donde cada pausa se produce en una línea de cuadrícula.

El orden es importante. Las piezas también son distinguibles, por lo que las dos piezas en cada extremo de una barra de chocolate de 1 por 3 no son equivalentes.

Por ejemplo, para un bloque de 2 por 2 tenemos:

 _ _            _   _            _   _            _   _
|_‖_|    ->    |‗| |_|    ->    |_| |‗|    ->    |_| |_|
|_‖_|          |_| |_|           _  |_|           _   _
                                |_|              |_| |_|


 _ _            _   _            _   _            _   _
|_‖_|    ->    |_| |‗|    ->    |‗| |_|    ->    |_| |_|
|_‖_|          |_| |_|          |_|  _            _   _
                                    |_|          |_| |_|


 _ _            _ _              _   _            _   _
|‗|‗|    ->    |_‖_|      ->    |_| |_|    ->    |_| |_|
|_|_|           _ _               _ _             _   _
               |_|_|             |_‖_|           |_| |_|


 _ _            _ _               _ _             _   _
|‗|‗|    ->    |_|_|      ->     |_‖_|    ->     |_| |_|
|_|_|           _ _              _   _            _   _
               |_‖_|            |_| |_|          |_| |_|

Por lo tanto, hay 4 formas de dividir una barra de chocolate de 2 por 2.

Reglas

  • La entrada será dos enteros a través de la entrada de función, STDIN, línea de comando o similar. Salida de un solo número, el número de formas de romper la barra de chocolate.

  • Dado que los números aumentan bastante rápido, no se preocupe si la salida excede los límites enteros de su idioma; su envío será válido siempre que el algoritmo funcione teóricamente para todas las entradas posibles.

Casos de prueba

El resultado no depende del orden de m,n, por lo que los casos de prueba se enumeran de manera tal m <= n.

1 1 -> 1
1 2 -> 1
1 3 -> 2
1 4 -> 6
1 5 -> 24
1 10 -> 362880

2 2 -> 4
2 3 -> 56
2 4 -> 1712
2 5 -> 92800
2 10 -> 11106033743298560

3 3 -> 9408
3 4 -> 4948992
3 5 -> 6085088256
3 10 -> 76209753666310470268511846400

4 4 -> 63352393728

A261964 son los números de chocolate dispuestos en un triángulo de tal manera que cada fila corresponde a la suma m+n.

Sp3000
fuente

Respuestas:

7

Mathematica, 85 bytes

f=If[##==1,1,Tr[Sum[Binomial[1##-2,i#-1]f[i,#]f[#2-i,#],{i,#2-1}]&@@@{{##},{#2,#}}]]&

Caso de prueba

f[4,4]
(* 63352393728 *)
njpipeorgan
fuente
3

Python 3, 168 , 156 , 147 bytes

Mejoras realizadas gracias al chat

f=lambda n:n<1or n*f(n-1);a=lambda m,n,c=lambda m,n:sum(f(m*n-2)/f(i*n-1)/f((m-i)*n-1)*a(i,n)*a(m-i,n)for i in range(1,m)):+(m+n<4)or c(m,n)+c(n,m)

Sin golf:

f=lambda n:n<1or n*f(n-1) # Factorial
def a(m, n):
    if m+n < 4:
        return 1
    first = 0
    for i in range(1,m):
        first += f(m*n-2) * 1/f(i*n-1) * 1/f((m-i)*n-1) * a(i,n) * a(m-i,n)
    second = 0
    for i in range(1,n):
        second += f(m*n-2) * 1/f(i*m-1) * 1/f((n-i)*m-1) * a(i,m) * a(n-i,m)
    return first + second

El algoritmo se basó en este documento .

Probablemente podría reducirlo mucho más, simplemente no estoy seguro de dónde

Cameron Aavik
fuente
3

R, 208 198 bytes

f=function(m,n){g=function(i,j){a=0;if(j>1)for(x in 2:j-1)a=a+choose(j*i-2,x*i-1)*M[x,i]*M[j-x,i];a};s=max(m,n);M=matrix(1,s,s);for(i in 1:s)for(j in 1:s)if(i*j>2)M[i,j]=M[j,i]=g(i,j)+g(j,i);M[m,n]}

Sangrado, con nuevas líneas:

f = function(m,n){
    g=function(i,j){
        a = 0
        if(j>1) for(x in 2:j-1) a = a + choose(j*i-2,x*i-1) * M[x,i] * M[j-x,i]
        a
    }
    s = max(m,n)
    M = matrix(1,s,s)
    for(i in 1:s) for(j in 1:s) if(i*j>2) M[i,j] = M[j,i] = g(i,j) + g(j,i)
    M[m,n]
}

Uso:

> f(3,1)
[1] 2
> f(3,2)
[1] 56
> f(3,3)
[1] 9408
> f(4,3)
[1] 4948992
> f(5,3)
[1] 6085088256
plannapus
fuente
En teoría, se puede escribir una versión recursiva más corta de ca. 160 bytes, pero alcanza rápidamente el límite de recursión predeterminado y el tamaño predeterminado de la pila de protección y la modificación de estos valores predeterminados (respectivamente usando options(expressions=...)y argumento --max-ppsize=) daría como resultado un código más largo que este.
plannapus
Puede guardar dos bytes omitiendo f=.
Alex A.
2

Python 2, 135 bytes

C=lambda A:sum(C(A[:i]+A[i+1:]+[(c,H),(W-c,H)])for i,Q in enumerate(A)for W,H in(Q,Q[::-1])for c in range(1,W))or 1
print C([input()])

Esto es lo que se me ocurrió. Es realmente lento, pero aquí hay una versión más rápida (necesita repoze.lru ):

from repoze.lru import lru_cache
C=lru_cache(maxsize=9999)(lambda A:sum(C(tuple(sorted(A[:i]+A[i+1:]+((c,H),(W-c,H)))))for i,Q in enumerate(A)for W,H in(Q,Q[::-1])for c in range(1,W))or 1)
print C((input(),))

Ejemplos

$ time python2 chocolate.py <<< 2,5
92800

real    0m2.954s
user    0m0.000s
sys     0m0.015s

$ time python2 chocolate-fast.py <<< 3,5
6085088256

real    0m0.106s
user    0m0.000s
sys     0m0.015s

Explicación

El código define una función Cque toma una matriz de piezas. El algoritmo es como tal:

  1. for i,Q in enumerate(A): recorre el conjunto de piezas.
  2. for W,H in(Q,Q[::-1]): calcular formas dos veces, girando 90 grados.
  3. for c in range(1,W): recorre las posibles posiciones para dividir.
  4. A[:i]+A[i+1:]+[(c,H),(W-c,H)]: obtenga una lista sin la pieza dividida y con las dos piezas nuevas.
  5. C(…): llama a la función nuevamente en esa lista.
  6. sum(…): suma los resultados para cada posible división.
  7. or 1: si no hay divisiones posibles, hay exactamente una forma de dividir el chocolate.

Finalmente, el código se llama con una matriz que contiene la entrada.

PurkkaKoodari
fuente
1

ES6, 141 bytes

c=(m,n)=>(f=n=>n<2||n*f(n-1),h=(m,n)=>[...Array(m-1)].reduce((t,_,i)=>t+f(m*n-2)/f(++i*n-1)/f((m-i)*n-1)*c(i,n)*c(m-i,n),0),h(m,n)+h(n,m))||1

Basado en la fórmula encontrada por @CameronAavik. Sin golf:

function fact(n) {
    return n < 2 ? 1 : n * f(n - 1);
}
function half(m, n) {
    total = 0;
    for (i = 1; i < m; i++)
        total += fact(m * n - 2) / fact(i * n - 1) / fact((m - i) * n - 1) * choc(i, n) * choc(m - i, n)
    return total;
}
function choc(m, n) {
    total = half(m, n) + half(n, m);
    if (!total) total = 1;
    return total;
}
Neil
fuente