Jest to względnie wydajne rozwiązanie, obliczając wszystkie pary gcd, usuwając duplikaty, a następnie rekursując. To czynność polegająca na usuwaniu duplikatów przed ponownym użyciem sprawia, że jest to wydajne.
Wyjaśnię algorytm bardziej szczegółowo poniżej, ale najpierw pomaga zdefiniować operator binarny . Jeśli S , T są zestawami liczb całkowitych dodatnich, zdefiniuj⊗S,T
S⊗T={gcd(s,t):s∈S,t∈T}.
Zauważ, że i | S ⊗ T | ≤ 10 9 (w twoim problemie); zazwyczaj S ⊗ T będzie nawet mniejszy niż sugeruje jedna z tych granic, co pomaga zwiększyć efektywność algorytmu. Zauważ też, że możemy obliczyć S ⊗ T za pomocą | S | × | T | operacje gcd przez proste wyliczenie.|S⊗T|≤|S|×|T||S⊗T|≤109S⊗TS⊗T|S|×|T|
Przy tej notacji oto algorytm. Niech będzie wejściowym zestawem liczb. Oblicz S 2 = S 1 ⊗ S 1 , następnie S 3 = S 1 ⊗ S 2 , następnie S 4 = S 1 ⊗ S 3 i tak dalej. Znajdź najmniejszy k taki, że 1 ∈ S k ale 1 ∉ S k - 1 . Wtedy wiesz, że rozmiar najmniejszego takiego podzbioru wynosi kS1S2=S1⊗S1S3=S1⊗S2S4=S1⊗S3k1∈Sk1∉Sk−1k. Jeśli chcesz również przedstawić konkretny przykład takiego podzbioru, zachowując wskaźniki wsteczne, możesz łatwo zrekonstruować taki zestaw.
Będzie to stosunkowo wydajne, ponieważ żaden z zestawów pośrednich nie wzrośnie powyżej (w rzeczywistości ich rozmiar prawdopodobnie będzie znacznie mniejszy niż ten), a czas działania wymaga około 500 × ( | S 1 | + | S 2 | + ⋯ ) operacje gcd.109500×(|S1|+|S2|+⋯)
Oto optymalizacja, która może jeszcze bardziej poprawić wydajność. Zasadniczo możesz użyć iterowanego podwajania, aby znaleźć najmniejsze takie jak 1 ∈ S k . W szczególności dla każdego elementu x ∈ S i śledzimy najmniejszy podzbiór S 1, którego gcd wynosi x i którego rozmiar wynosi ≤ i . (Kiedy usuwasz duplikaty, rozwiązujesz powiązania na korzyść mniejszego podzbioru.) Teraz zamiast obliczać sekwencję dziewięciu zestawów S 1 , S 2 , S 3 , S 4 ,k1∈Skx∈SiS1x≤i , zamiast tego obliczamy sekwencję pięciu zestawów S 1 , S 2 , S 4 , S 8 , S 9 , obliczając S 2 = S 1 ⊗ S 1 , następnie S 4 = S 2 ⊗ S 2 , a następnie S 8 = S 4 ⊗ S 4 , a następnie S 9 = S 1 × S 8S1,S2,S3,S4,…,S9S1,S2,S4,S8,S9S2=S1⊗S1S4=S2⊗S2S8=S4⊗S4S9=S1×S8. Idąc, znajdź pierwszą taką, że 1 ∈ S k . Po znalezieniu k takiego, że 1 ∈ S k , możesz natychmiast zatrzymać: możesz znaleźć najmniejszy podzbiór, którego gcd ma wartość 1 , patrząc na podzbiór powiązany z 1 . Możesz więc zatrzymać się, gdy tylko osiągniesz zestaw S k, taki jak 1 ∈ S k , co pozwala ci zatrzymać się wcześniej, jeśli znajdziesz mniejszy podzbiór.k∈[1,2,4,8,9]1∈Skk1∈Sk11Sk1∈Sk
Powinno to być wydajne czasowo i zajmować mało miejsca. Aby zaoszczędzić miejsce, dla każdego elementu nie musisz przechowywać całego zestawu: wystarczy przechowywać dwa wskaźniki wsteczne (więc dwa elementy S i , S j , z których pobrałeś gcd, aby uzyskać x ) i opcjonalnie rozmiar odpowiedniego podzbioru.x∈SkSi,Sjx
Zasadniczo można zastąpić sekwencję dowolnym innym łańcuchem dodawania . Nie wiem, czy jakiś inny łańcuch dodatków będzie lepszy. Optymalny wybór może zależeć od rozkładu poprawnych odpowiedzi i oczekiwanych rozmiarów zbiorów S k , co nie jest dla mnie jasne, ale prawdopodobnie można je uzyskać empirycznie poprzez eksperymenty.[1,2,4,8,9]Sk
Kredyty: Moje podziękowania dla KWillets za pomysł przechowywania podzbioru liczb wraz z każdym elementem , który pozwala wcześnie się zatrzymać.Si