He dedicado una entrada bastante compleja, hace un tiempo atrás, sobre la forma de obtener combinaciones en base a distintos caracteres, para, por ejemplo, romper una contraseña. Y digo mal "combinación", ya que una contraseña o password o clave es, en realidad, una "permutación". ¿La diferencia? en una combinación el orden de los elementos no importa: es lo mismo mezclar tomates, cebollas y lechuga que cebollas, lechugas y tomates. Pero en una permutación no es igual "abc" que "bca". Aquí el orden sí posee importancia, y mucha. Si alguien tiene alguna duda, que la proxima vez ingrese los caracteres de su contraseña al webmail en el orden que le plazca, y verá como el ingreso será rechazado.
Un lector que no está ducho en la implementación de macros, y que a su vez posee unos pocos números a combinar, me solicita otra solución, mas sencilla. Le remiten 5 o 6 cheques por día, de distintos valores, junto a una o dos facturas de compra. El sabe que esa factura se pagó con algunos de los cheques, pero no sabe cuales. Manualmente (y con calculadora en mano) debe "mezclar" esos cheques hasta dar con los que forman el importe de la factura, que pueden ser dos, cuatro, seis, etc. La solución no es complicada (hay otra forma de solucionarlo con la herramienta "solver", pero es mas difícil) y viene de la mano de lo que autodenominé "tabla binaria". Realmente no se si se llama así, pero la bauticé de esa forma por que nunca me enteré de su verdadero nombre.
la tan "mentada" tabla binaria... o como se llame.
[+/-] Ver el resto / Ocultar
En el encabezado de mi tabla verán una progresión binaria, muy familiar en el mundo de los "bits": 1, 2, 4, 8, 16, 32, 64, 128, 256, etc, etc, etc. El ejemplo sólo abarca hasta el 16, y luego veremos el por qué.
Esas cinco "progresiones binarias" van del 1 al 16 y cada una, digamos, se corresponde con uno de los cheques a combinar. En total tengo 5 cheques. Ahora bien... con cinco elementos ¿cuantas combinaciones posibles existen? La fórmula es sencilla: 2 elevado a la n, menos 1:
(2n ) - 1
donde n es la cantidad de elementos. En este caso, los cheques. Entonces:
(25 ) - 1
lo que nos arroja 15 ( 2 elevado a la 5 es = 16, menos 1 = 15). O sea: con 5 elementos puedo formar hasta 15 combinaciones. Y esas quince combinaciones son las que muestro en la columna B.
Creo que hasta aquí vamos bien. ¿Y que hacen esos números binarios? Sencillo: forman cada una de las combinaciones posibles.
Observemos el número 3: tiene un 1 debajo del 1 y del 2, ya que en binario 3 es 11. Otro ejemplo: el 5. Vemos que debajo del 1 y del 4 hay un 1 y... si, no queda otra, 5 en binario es 101.
Ese 1 que observamos dentro de la tabla actúa como un interruptor, en su fase positiva. El 0 lo hace de igual forma, pero negativo. ¿Como formamos el número 10? Si miramos la tabla, con un 1 debajo del 8 y otro debajo del 2. O sea: 8 + 2 = 10.
Resumiendo: cuando debajo de uno de los números de la progresión binaria hay un número 1, sumo.
Esto a simple vista no tiene mucho sentido, pero lo entenderán perfectamente con una pequeña modificación a la tabla:
debajo de cada "progresión binaria" coloqué los importes de los 5 cheques que mi lector recibió en uno de sus días de trabajo. A la derecha pueden ver la suma total de esos 5 valores.
Dije que cada 1 de la tabla actuaba como un interruptor en positivo, es decir, VERDADERO. Ahora solo me queda sumar (fila x fila, hasta la nro 15 de la tabla) todos los cheques que debajo, en la tabla, tengan un 1.
Para facilitar el cálculo y omitir el uso de columnas auxiliares, aplicaré la funcion SUMAPRODUCTO(Matriz1, Matriz2, Matrizn) que multiplica y suma los elementos de dos o mas matrices:
y el resultado se presenta en la columna H: ¿que hicimos? multiplicamos la fila de los cheques por cada una de las filas binarias. Noten que la fila de los cheques tiene referencia absoluta, para que al copiar la función hacia abajo no se desplace.
Ya está, a la derecha podemos observar el resultado de todas y cada una de las combinaciones posibles. Y si lo analizamos de a poco... es muy sencillo. Veamos:
1) El primer resultado es 1238,32. Si nos fijamos bien, solo ese cheque tiene un 1 debajo, así que a ese cheque lo multipliqué con 1 mediante SUMAPRODUCTO(), a todos los demas por 0. Internamente la función hizo: (1238,32 * 1) + (3621,98 * 0) + (416,78 * 0) + (10978,32 * 0) + (862,89 * 0), lo que es igual a: 1238,32 + 0 + 0 + 0 + 0 = 1238,32
2) El segundo resultado es 3621,98. Solo encontró un 1 debajo del mencionado valor, así que se aplica el mismo criterio del punto anterior. Hay un solo 1 en toda la fila.
3) El tercer resultado es 4860,30. Y aquí está el asunto... justo debajo de los valores 3621,98 y 1238,32 se encuentran un 1. Y la función los sumó, y de allí ese 4860,30 de resultado, que no son otra cosa que la combinación (sumada, en este caso) de los citados cheques.
Si seguimos aplicando la misma lógica línea por línea, nos daremos cuenta que la función sumó, en cada línea, todos los cheques que debajo poseían un 1. Y así hasta la fila 15, completando la totalidad de las posibles combinatorias.
Para presentar este trabajo a un cliente podríamos mejorar un poco la interface:
siempre les digo que soy un verdadero animal para diseñar el entorno gráfico, pero bué... creo que mejoró un poco.
Ahora le damos la posibilidad de ingresar el monto total de la factura, al pié de la tabla.
La frase "La combinación se encuentra en la fila XX de la tabla" se logra con la siguiente función:
="La combinación se encuentra en la fila "&COINCIDIR(E20;H4:H18;0)&" de la tabla"
Busco el importe de la factura en el rango de los resultados, devolviendo la posición dentro de esa matriz. Si no hay coincidencias nos devolverá un error, así que deberemos aplicar formato condicional o tomar otros recaudos para que "no quede tan feo".
Que les sea de utilidad y espero sus consultas, de existir alguna.
Hola buenas, yo tengo una duda. Necesito hace un Floyd de 6x6. Tengo 3 letras, K ; I ; J, y tengo que darle un valor de 1 a 6 sin que se repitan. Se que son 120 combinaciones pero me gustaría saber si se puede hacer automáticamente con excel o acces
ResponderEliminarla verdad que es la primera vez que veo el término "floyd". quizás lo conozca bajo otra denominación, pero por ahora no me doy cuenta.
ResponderEliminarte comento: pasame un archivo a la direccion de mail que figura debajo del formulario, así veo bien lo que necesitas y armo una entrada al respecto. con visual basic es muy sencillo generar aleatorios entre dos valores, sin repetir. quedo al aguardo de tus noticias.
estimado: aquí te dejo un pequeño código que genera 3 aleatorios (todos distintos entre si, entre 1 y 6) y los coloca dentro de un rango al que llamé "cuadro". es muy sencillo de modificar, por si el día de mañana necesitaras ampliar la cantidad de aleatorios o entre que valores deben moverse los resultados:
ResponderEliminarSub TresAleatorios()
Dim Alea, Cont As Byte
Cont = 0
Randomize
Range("cuadro").ClearContents
'el bucle se ejecutará mientras el valor
'de Cont sea menor a 3. si necesitas generar
'mas aleatorios, solamente modifica este
'valor por otro (ej: 10, 15, 7, etc)
While Cont < 3
deNuevo:
'genero el aletorio:
Alea = Int((6 * Rnd) + 1)
'ahora busco en el rango si ese
'aleatorio existe:
On Error Resume Next
f = Range("cuadro").Find(Alea).Row
'si arroja un error quiere decir que
'el valor NO está, así que lo coloco:
If Err.Number <> 0 Then
Cont = Cont + 1
Range("cuadro").Cells(Cont).Value = Alea
Err.Clear
Else
'si no hay error, el valor ya se generó,
'así que repito las acciones:
GoTo deNuevo
End If
Wend
End Sub
aqui el link al archivo:
https://sites.google.com/site/damianomarsilva2/aleatorios_1-6.xls
perdona la ignorancia de mi primer comentario, seguro estás haciendo referencia al algoritmo de "floyd-warshall", el que te permite encontrar el camino mínimo.
ResponderEliminar