È possibile risolverlo in modo relativamente efficiente calcolando tutti i gcd a coppie, rimuovendo i duplicati e quindi ricorrendo. È l'atto di rimuovere i duplicati prima di ricorrere che lo rende efficiente.
Spiegherò l'algoritmo in modo più dettagliato di seguito, ma prima aiuta a definire un operatore binario . Se sono insiemi di numeri interi positivi, definireS , T⊗S,T
S⊗T={gcd(s,t):s∈S,t∈T}.
Si noti chee (nel tuo problema); in genere, sarà anche più piccolo di quanto suggerisca uno di questi limiti, il che aiuta a rendere l'algoritmo efficiente. Inoltre, possiamo calcolare conoperazioni gcd per semplice enumerazione.| S ⊗ T | ≤ 10 9 S ⊗ T S ⊗ T | S | × | T ||S⊗T|≤|S|×|T||S⊗T|≤109S⊗TS⊗T|S|×|T|
Con questa notazione, ecco l'algoritmo. Lascia che sia l'insieme di numeri di input. Calcola , quindi , quindi e così via. Trova il più piccolo in modo tale che ma . Quindi sai che la dimensione del più piccolo sottoinsieme è . Se si desidera anche fornire un esempio concreto di tale sottoinsieme, mantenendo i puntatori posteriori è possibile ricostruire facilmente tale set.S1S2=S1⊗S1S3=S1⊗S2S4=S1⊗S3k1∈Sk1∉Sk−1k
Questo sarà relativamente efficiente, poiché nessuna delle serie intermedie cresce di dimensioni superiori a (in effetti, la loro dimensione sarà probabilmente molto più piccola di quella) e il tempo di esecuzione richiede circa operazioni gcd.109500×(|S1|+|S2|+⋯)
Ecco un'ottimizzazione che potrebbe migliorare ulteriormente l'efficienza. Fondamentalmente, puoi usare il raddoppio iterato per trovare il più piccolo tale che . In particolare, per ogni elemento , teniamo traccia del sottoinsieme più piccolo di cui gcd è e la cui dimensione è . (Quando rimuovete i duplicati, risolvete i legami a favore del sottoinsieme più piccolo.) Ora, anziché calcolare la sequenza di nove insiemi , invece la sequenza di cinque insiemi , calcolando , quindi , quindik1∈Skx∈SiS1x≤iS1,S2,S3,S4,…,S9S1,S2,S4,S8,S9S2=S1⊗S1S4=S2⊗S2S8=S4⊗S4 , quindi . Mentre , trova il primo tale che . Una volta trovato tale che , puoi immediatamente fermarti: puoi trovare il sottoinsieme più piccolo il cui gcd è guardando il sottoinsieme associato a . Quindi, puoi fermarti non appena raggiungi un set tale che , che ti consente di fermarti presto se trovi un sottoinsieme più piccolo.S9=S1×S8k∈[1,2,4,8,9]1∈Skk1∈Sk11Sk1∈Sk
Questo dovrebbe essere efficiente in termini di tempo e spazio. Per risparmiare spazio, per ogni elemento , non è necessario memorizzare l'intero set: è sufficiente memorizzare due backpointer (quindi i due elementi di cui hai preso il gcd, per ottenere ) e facoltativamente la dimensione del sottoinsieme corrispondente.x∈SkSi,Sjx
In linea di principio, è possibile sostituire la sequenza con qualsiasi altra catena di addizione . Non so se qualche altra catena di aggiunte sarà migliore. La scelta ottimale potrebbe dipendere dalla distribuzione delle risposte corrette e dalle dimensioni previste degli insiemi , il che non mi è chiaro, ma che probabilmente può essere derivato empiricamente attraverso la sperimentazione.[1,2,4,8,9]Sk
Riconoscimenti: i miei ringraziamenti a KWillets per l'idea di memorizzare un sottoinsieme di numeri insieme a ciascun elemento di , che consente di fermarsi presto.Si