Cómo usar la programación dinámica para contar las formas en que podemos escribir un entero dado como una suma ordenada de enteros pequeños

Sea C [math] (n, m) [/ math] el número de formas de escribir [math] n [/ math] como una suma ordenada de enteros positivos que no exceden [math] m [/ math].

La forma básica de encontrar una recurrencia / resolver un problema de conteo usando programación dinámica es la siguiente:

Primero, imagina construir la solución de forma incremental, como una secuencia de pasos. Aquí, esto es natural, podemos elegir un elemento de la suma a la vez, de izquierda a derecha.

Luego, considera todas las posibilidades de lo que sucede en el primer paso. El primer número [matemático] i [/ matemático] que elijamos estará entre 1 y [matemático] \ min (n, m) [/ matemático], inclusive. (Por lo general, será entre 1 y [matemáticas] m [/ matemáticas], inclusive, pero para las pequeñas [matemáticas] n [/ matemáticas] también debemos asegurarnos de no exceder eso).

Cada elección de [math] i [/ math] nos da un conjunto diferente de soluciones. Más precisamente, esos conjuntos de soluciones son mutuamente disjuntos. Por lo tanto, podemos contar el número de soluciones en cada caso por separado, y luego simplemente las sumamos.

Entonces, veamos un caso particular. El primer elemento de la suma es [math] i [/ math]. Para finalizar la suma, tenemos que escribir [math] ni [/ math] como una suma de elementos que no exceda [math] m [/ math]. ¿Luce familiar? Debería, porque es el mismo problema que antes. Usando nuestra notación, hay formas [math] C (ni, m) [/ math] de hacerlo.

Esto nos lleva a la siguiente recurrencia:

  • caso base: [matemática] C (0, m) = 1 [/ matemática], la única forma es la suma vacía
  • caso recursivo: [matemática] \ forall n> 0: C (n, m) = \ sum_ {i = 1} ^ {\ min (n, m)} C (ni, m) [/ math]

La evaluación de la recurrencia anterior lleva tiempo [matemático] O (nm) [/ matemático]. Hay una manera simple de optimizar el cálculo a [matemáticas] O (n) [/ matemáticas], lo dejaré como un ejercicio para el lector 🙂

No estoy tan seguro si entiendo el problema por completo. ¿No debería ser la respuesta en el ejemplo 11? Si estamos dividiendo 5 en como máximo 3 enteros, entonces

5 = 5 = 1 + 4 = 4 + 1 = 2 + 3 = 3 + 2 = 1 + 1 + 3 = 1 + 3 + 1 = 3 + 1 + 1 = 1 + 2 + 2 = 2 + 1 + 2 = 2 + 2 + 1

Entonces hay 11 formas posibles.

Si esto es lo que pretendía, una forma posible de resolver este problema es escribir un programa de programación dinámica de arriba hacia abajo (es decir, memorización).

// por Luke Kim
#include
#include
#include
#include
usando el espacio de nombres estándar;

#define MAXN 51
#define MAXK 51

caché int [MAXN] [MAXK];
int resolver (int n, int k) {
si (k <0) devuelve 0;
if (n == 0 && k> = 0) devuelve 1;
int & ret = caché [n] [k];
if (ret! = -1) devuelve ret;
ret = 0;
para (int i = 1; i <= n; i ++) {
if (ni> = 0) ret + = resolver (ni, k-1);
}
volver ret;
}

int main () {
ios_base :: sync_with_stdio (falso);
cin.tie (NULL);
int n, k; // el número a particionar, número máximo de particiones
cin >> n >> k;
memset (caché, -1, sizeof (caché));
cout << resolver (n, k) << endl;
devuelve 0;
}

Pensar en una función

countPartitions (int N, int max)

para encontrar el resultado intente todas las posiciones de 1 a N para dividir la secuencia en dos mitades. Desea max = a a la izquierda y max = b a la derecha, de modo que a + b + 1 = max.

Si no necesita usar la Programación dinámica, puede usar mi programa C (basado en un algoritmo de Donald Knuth).

http://gcrhoads.byethost4.com/Co

More Interesting

¿Es esta una buena prueba de aritmética modular?

¿La integral de una función impar compleja también es 0 como en el análisis real?

Cómo encontrar [matemática] n [/ matemática] de modo que el resto de la división euclidiana de [matemática] n ^ 2 + n [/ matemática] por [matemática] 5 [/ matemática] sea igual a [matemática] 2 [/ matemáticas], donde [matemáticas] n \ in \ Z [/ matemáticas]

¿Es el hecho de que la hipótesis de Riemann es una prueba empíricamente comprobable de que es demostrable?

Si [math] pq [/ math] divide [math] p ^ 2 + q ^ 2 + r ^ 2 + s ^ 2 [/ math], donde [math] p, q, r, s [/ math] son ​​positivos enteros, [matemáticas] p [/ matemáticas] y [matemáticas] q [/ matemáticas] son ​​relativamente primos, [matemáticas] r [/ matemáticas] y [matemáticas] s [/ matemáticas] también lo son, y [matemáticas] pq = rs [/ math], ¿al menos uno de los números tiene que ser 1?

¿Cuál es la relación entre la hipótesis de Riemann y la conjetura de Birch y Swinnerton-Dyer?

¿Hay infinitos enteros positivos que no se pueden escribir como ([matemáticas] (a ^ 2 + d ^ 2) / (bc)) * ((b ^ 2 + c ^ 2) / (ad)) [/ matemáticas], donde a, b, cyd son enteros relativamente primos y positivos?

¿Crees que la hipótesis de Riemann es incluso posible de probar o refutar y qué tal el resto de los problemas del Milenio?

¿Para qué sirve la función aritmética?

¿Existe un algoritmo de búsqueda local para problemas que contienen números enteros o incluso variables enteras no ordenadas?