Bueno, seguramente podemos hacer ocho bucles for anidados, pero eso es feo, molesto de escribir, propenso a errores y no se generaliza bien. En cambio, aquí hay una bonita solución.
Considere el siguiente “algoritmo”:
- Comience con un número “vacío” (es decir, todavía no tiene dígitos).
- Para cada valor de 0 a 9, tome tantas copias del dígito como desee y añádalas al número.
Claramente, usando este “algoritmo” podemos generar exactamente los números que queremos. Si solo queremos números de dígitos [matemáticos] [/ matemáticos], todo lo que tenemos que hacer es prestar atención en el paso 2 y asegurarnos de que tomamos un total de dígitos exactamente [matemáticos] d [/ matemáticos].
Si queremos una forma más formal de decir “en total, tome exactamente [math] d [/ math] dígitos”, podemos reformular el mismo “algoritmo” de la siguiente manera:
- Cómo resolver un problema de optimización de restricciones
- ¿Cuántas iteraciones hay, si cada iteración resuelve el log m del m restante?
- N es un número entero y el producto de todos sus factores es igual a N ^ 2. La suma de todos los factores de N, excluyendo N, es 57. ¿Cuántos valores hay?
- ¿Cuál sería un enfoque / algoritmo eficiente para calcular el MCD por pares más alto a partir de una matriz de números dada?
- Dado un conjunto [matemática] S [/ matemática] de [matemática] 2 ^ n [/ matemática] cadenas binarias, [matemática] \ forall [/ matemática] [matemática] s_i \ en S [/ matemática] es de tamaño [matemática ] n [/ math] y asignado a [math] 0 [/ math] o [math] 1 [/ math], ¿podemos sintetizar un oráculo [math] f [/ math] que mapee las cadenas binarias, es decir, [math ] f: S \ rightarrow \ {0,1 \} [/ math]?
Comenzamos con un número “vacío” y establecemos el “dígito actual” en cero. Luego, en cualquier orden de nuestra elección, ejecutaremos los siguientes comandos:
- exactamente 9 veces: incremente el dígito actual
- exactamente d veces: agrega el dígito actual al número
Ahora podemos hacer las siguientes observaciones:
- Cada número que podemos generar usando el algoritmo anterior tiene la propiedad deseada. Cada vez que agregamos un dígito al número, es igual o mayor que el dígito anterior que agregamos, que es precisamente lo que queríamos.
- Podemos generar cada número válido usando el algoritmo anterior. Simplemente vaya dígito por dígito. Por ejemplo, para generar 334, incremente el dígito actual tres veces (para cambiarlo de 0 a 3), añádalo al número actual dos veces (para cambiarlo de “” a “33”), luego incremente el dígito actual nuevamente (para 4), añádalo al número (“334”) y finalmente incremente el dígito actual las últimas cinco veces.
- Diferentes secuencias de comandos producen diferentes números. Mire el primer comando “agregar” donde difieren. En ese paso, obviamente agregaríamos dos dígitos diferentes.
Por lo tanto, tenemos un algoritmo general que se ve de la siguiente manera:
- Ingrese [math] d [/ math]: el número de dígitos.
- Genere todas las secuencias de comandos [math] d + 9 [/ math], como se describió anteriormente. En C ++ podemos hacer esto de manera conveniente y eficiente usando la función STL
next_permutation
. - Para cada secuencia de comandos, calcule y envíe el número correspondiente.
Aquí hay una buena implementación de C ++ anotada:
// lee el número de dígitos
int D;
cin >> D;
// crea la matriz de “comandos”
// el comando 0 agrega el dígito actual, el comando 1 lo incrementa
comandos de vector (9 + D, 0);
para (int i = D; i <D + 9; ++ i) comandos [i] = 1;
// iterar sobre todas las secuencias de “comandos”
hacer {
// procesa la secuencia actual de “comandos”
string current_number = “”;
char current_digit = ‘0’;
para (int cmd: comandos) {
si (cmd) {
++ current_digit;
} más {
número_corriente + = dígito_corriente;
}
}
cout << número_actual << endl;
} while (next_permutation (command.begin (), command.end ()));
Como beneficio final, al iterar sobre las secuencias de comandos en un orden elegido correctamente obtenemos la salida en orden ordenado.