Es posible resolver esto de manera relativamente eficiente calculando todos los gcd de pares, eliminando duplicados y luego recurriendo. Es el acto de eliminar duplicados antes de recurrir lo que lo hace eficiente.
Explicaré el algoritmo con más detalle a continuación, pero primero, ayuda a definir un operador binario . Si son conjuntos de enteros positivos, definaS , T⊗S,T
S⊗T={gcd(s,t):s∈S,t∈T}.
Tenga en cuenta quey (en su problema); típicamente, será aún más pequeño de lo que sugiere cualquiera de esos límites, lo que ayuda a que el algoritmo sea eficiente. También tenga en cuenta que podemos calcular conoperaciones de gcd por enumeración simple.El | S ⊗ T | ≤ 10 9 S ⊗ T S ⊗ T | S | × | T ||S⊗T|≤|S|×|T||S⊗T|≤109S⊗TS⊗ TEl | SEl | × | TEl |
Con esa notación, aquí está el algoritmo. Deje que sea el conjunto de números de entrada. Calcule , luego , luego , y así sucesivamente. Encuentre la más pequeña tal que pero . Entonces sabes que el tamaño del subconjunto más pequeño es . Si también desea generar un ejemplo concreto de dicho subconjunto, manteniendo los punteros hacia atrás puede reconstruir fácilmente dicho conjunto.S 2 = S 1 ⊗ S 1 S 3 = S 1 ⊗ S 2 S 4 = S 1 ⊗ S 3 k 1 ∈ S k 1 ∉ S k - 1 kS1S2= S1⊗ S1S3= S1⊗ S2S4 4= S1⊗ S3k1 ∈ Sk1 ∉ Sk - 1k
Esto será relativamente eficiente, ya que ninguno de los conjuntos intermedios crece en tamaño por encima de (de hecho, su tamaño probablemente será mucho más pequeño que eso), y el tiempo de ejecución requiere aproximadamente operaciones gcd. 500 × ( | S 1 | + | S 2 | + ⋯ )109 9500 × ( | S1El | + | S2El | +⋯)
Aquí hay una optimización que podría mejorar aún más la eficiencia. Básicamente, puede usar la duplicación iterada para encontrar la más pequeña de manera que . En particular, para cada elemento , hacemos un seguimiento del subconjunto más pequeño de cuyo mcd es y cuyo tamaño es . (Cuando elimina duplicados, resuelve los vínculos a favor del subconjunto que es más pequeño). Ahora, en lugar de calcular la secuencia de nueve conjuntos , calculamos la secuencia de cinco conjuntos , calculando , luego , luego1 ∈ S k x ∈ S i S 1 x ≤ i S 1 , S 2 , S 3 , S 4 , … , S 9 S 1 , S 2 , S 4 , S 8 , S 9 S 2 = S 1 ⊗ S 1 S 4 = S 2 ⊗ S 2 Sk1∈Skx∈SiS1x≤iS1,S2,S3,S4,…,S9S1,S2,S4,S8,S9S2=S1⊗S1S4=S2⊗S2S 9 = S 1 × S 8 k ∈ [ 1 , 2 , 4 , 8 , 9 ] 1 ∈ S k k 1 ∈ S k 1 1 S k 1 ∈ S kS8=S4⊗S4 , luego . A medida que avanza, encuentre la primera tal que . Una vez que haya encontrado tal que , puede detenerse de inmediato: puede encontrar el subconjunto más pequeño cuyo mcd es mirando el subconjunto asociado con . Por lo tanto, puede detenerse tan pronto como llegue a un conjunto tal que , lo que le permite detenerse temprano si encuentra un subconjunto más pequeño.S9=S1×S8k∈[1,2,4,8,9]1∈Skk1∈Sk11Sk1∈Sk
Esto debería ser eficiente en el tiempo y en el espacio. Para ahorrar espacio, para cada elemento , no necesita almacenar todo el conjunto: es suficiente para almacenar dos backpointers (por lo que los dos elementos de que tomó el mcd, para obtener ) y opcionalmente el tamaño del subconjunto correspondiente.S i , S j xx∈SkSi,Sjx
En principio, puede reemplazar la secuencia por cualquier otra cadena de adición . No sé si alguna otra cadena de adición será mejor. La elección óptima podría depender de la distribución de las respuestas correctas y los tamaños esperados de los conjuntos , lo cual no es claro para mí, pero probablemente puede derivarse empíricamente a través de la experimentación.S k[1,2,4,8,9]Sk
Créditos: Mi agradecimiento a KWillets por la idea de almacenar un subconjunto de números junto con cada elemento de , lo que permite parar antes.Si