2009-12-09 22 views
6

Próbuję napisać program, aby znaleźć największy czynnik główny bardzo dużej liczby i próbowałem kilku metod z różnym sukcesem. Wszystkie te, które znalazłem do tej pory, były niewiarygodnie powolne. Miałem myśli, i zastanawiam się, czy jest to prawidłowy podejście:Problemy z liczbami pierwszymi

long number = input; 

while(notPrime(number)) 
{ 
    number = number/getLowestDivisiblePrimeNumber(); 
} 

return number; 

Takie podejście ma wejście, i wykonaj następujące czynności:

200 -> 100 -> 50 -> 25 - > 5 (powrót)

90 -> 45 -> 15 -> 5 (powrót)

dzieli currentNum wielokrotnie przez najmniejszą liczbą podzielną (najczęściej 2 lub 3), aż sama currentNum jest liczbą (nie nie jest podzielną liczbą pierwszą mniejszą niż kwadrat od bieżącegoNUM) i zakłada, że ​​jest to największy est czynnik pierwotny pierwotnego wejścia.

Czy to zawsze zadziała? Jeśli nie, czy ktoś może mi podać kontrprzykład?

-

Edycja: Przez bardzo duże, to znaczy o 2^40 lub 10^11.

+5

Chciałbym zobaczyć realizację swojej magicznej 'notPrime()' funkcyjnego. :) –

+3

heh, to proste: notPrime (n) = (getLowestDivisiblePrimeNumber (n) == n). –

+0

Szczerze mówiąc, używam tam (prawda), po prostu było to łatwiejsze do wytłumaczenia w ten sposób. Moja metoda getLowestDivisiblePrime odnosi się do klasy podstawowej ArrayList primeList; Jeśli nie istnieje żadna podzielna liczba pierwsza w primeList, znajduje następną liczbę pierwszą do dodania do primeList i kontynuuje to, dopóki nie znajdzie liczby pierwszej, której "liczba" jest dzielona przez (i później odniesie się do większej listy liczb pierwszych) , lub dopóki największa liczba pierwsza w primeList nie jest większa niż sqaureroot "number". Nie ma tam żadnej magii, choć mam nadzieję, że będzie to dość skuteczne. = P – Jonathan

Odpowiedz

16

To zawsze będzie działać z powodu Unique Prime Factorization Theorem.

+0

Dziękuję za cytowanie. =) – Jonathan

+2

Dla przypadków narożnych 0 i 1 nie są ani pierwszymi, ani złożonymi, a biorąc pod uwagę, że długa jest podpisana, musisz dowiedzieć się, jak chcesz obsługiwać liczby ujemne. –

2

Próbujesz znaleźć numer prime factors. To, co proponujesz, będzie działało, ale nadal będzie wolne dla dużych liczb. Powinieneś być wdzięczny za to, ponieważ większość współczesnych zabezpieczeń opiera się na tym, że jest to trudny problem.

+0

Na kropce! Pierwszą, która przychodzi na myśl, jest RSA. –

3

Z pewnością zadziała (zobacz Mark Byers' answer), ale w przypadku "bardzo dużych" wejść może zająć zbyt dużo czasu. Powinieneś zauważyć, że twój numer getLowestDivisiblePrimeNumber() ukrywa inną pętlę, więc ta operacja działa w O (N^2), i że w zależności od tego, co masz na myśli przez "bardzo duży", może to zadziałać na BigNums, która będzie powolna.

Możesz nieco przyspieszyć, zauważając, że twój algorytm nie musi nigdy sprawdzać współczynników mniejszych niż ostatni znaleziony.

+0

Zrobię to, dziękuję. =) – Jonathan

+0

Choć jest wybredny, mówi "długi" i używa "Java" w tagu pytającym, więc to tylko 2 ** 63 i nie jest to problem typu BigNum. Z drugiej strony leży dokumentacja. :) –

+0

@dalke: Ack. Widok słów "bardzo duży" utknął mi w rutynie. I myślę, że ulepszona wersja może działać w (dość powolnym) czasie liniowym, chociaż metoda, którą sugeruje OP, będzie zużywać dużo przestrzeni ... – dmckee

21

Metoda będzie działać, ale będzie wolno. "Jak duże są twoje liczby?" określa metodę użycia:

+1

Jestem pod wrażeniem twoich odniesień do algorytmów, o których nigdy nie słyszałem, ale: Czy te algorytmy nie są lepiej przystosowane do znajdowania * wszystkich * liczb pierwszych do określonego limitu, niż do faktorowania pojedynczej liczby? –

+0

Zgadzam się z Carlem. Chociaż nie mogę stwierdzić tego jako fakt (nie badałem wyżej wymienionych metod), uważam, że jest to bardzo skuteczna metoda znajdowania największego czynnika głównego. Jak zaimplementować notPrime() - lub raczej! Prime() - to zupełnie inna sprawa. – Jonathan

+0

@ Jonathan: Jak duży jest "bardzo duży"? –

1

Od szybkiego wyszukiwania po prostu zrobił, najszybszy znany sposób, aby uwzględniały liczba jest za pomocą metody krzywej eliptycznej.

Możesz spróbować rzucić swój numer na tym demo: http://www.alpertron.com.ar/ECM.HTM.

Jeśli to cię przekona, możesz spróbować ukraść kod (to nie jest zabawne, zapewniają link do niego!) Lub czytając teorię o tym gdzie indziej. Tutaj jest artykuł o Wikipedii: http://en.wikipedia.org/wiki/Lenstra_elliptic_curve_factorization, ale jestem zbyt głupi, aby to zrozumieć. Na szczęście to twój problem, nie mój! :)

0

Rzecz z Projektem Euler polega na tym, że zazwyczaj istnieje oczywista metoda brutalnej siły, która rozwiązuje problem, co zajmie trochę czasu. Ponieważ pytania stają się coraz trudniejsze, będziesz musiał wdrożyć sprytne rozwiązania.

Jednym ze sposobów rozwiązania tego problemu jest użycie pętli, która zawsze znajduje najmniejszy (dodatnią liczbę całkowitą) współczynnik liczby. Kiedy najmniejszym czynnikiem liczby jest ta liczba, to znalazłeś największy czynnik pierwszy!

Szczegółowy opis algorytmu:

Można to zrobić poprzez utrzymywanie trzy zmienne:

Liczba próbujesz Factor (A) Aktualna sklep dzielnik (B) największy sklep dzielnik (C)

Początkowo niech (A) będzie numerem, który Cię interesuje - w tym przypadku jest to 600851475143. Następnie pozwól (B) być 2. Mieć warunkowe, które sprawdza, czy (A) jest podzielna przez (B) . Jeśli jest podzielna, podziel (A) przez (B), zresetuj (B) na 2 i wróć do sprawdzenia, czy (A) jest podzielna przez (B). Inaczej, jeśli (A) nie jest podzielna przez (B), inkrement (B) o +1, a następnie sprawdź, czy (A) jest podzielna przez (B). Uruchom pętlę do momentu, w którym (A) wynosi 1. Zwrócony (3) będzie największym dzielnikiem głównym o wartości 600851475143.

Istnieje wiele sposobów, które można uczynić bardziej skutecznymi - zamiast zwiększać do następnej liczby całkowitej, można Zwiększenie do następnej koniecznej liczby całkowitej, a zamiast utrzymywania największego sklepu z dzielnikami, możesz po prostu zwrócić bieżący numer, gdy jego jedynym dzielnikiem jest sam. Jednak algorytm, który opisałem powyżej, będzie działał w sekundach niezależnie.

Realizacja w pytona jest następujący: -

def lpf(x): 
     lpf = 2; 
     while (x > lpf): 
       if (x%lpf==0): 
         x = x/lpf 
         lpf = 2 
       else: 
         lpf+=1; 
     print("Largest Prime Factor: %d" % (lpf)); 

def main(): 
     x = long(raw_input("Input long int:")) 
     lpf(x); 
     return 0; 

if __name__ == '__main__': 
    main() 

przykład: Znajdźmy największą doskonałą czynnik 105 przy użyciu metody opisanej powyżej.

Niech (A) = 105. (B) = 2 (zawsze zaczynamy od 2) i nie mamy jeszcze wartości dla (C).

Czy (A) jest podzielna przez (B)? Nie. Przyrost (B) o +1: (B) = 3. Czy jest (A) podzielna przez (B)? Tak. (105/3 = 35). Największy dzielnik jak dotąd znaleziony to 3. Let (C) = 3. Update (A) = 35. Reset (B) = 2.

Teraz jest (A) podzielny przez (B)? Nie. Przyrost (B) o +1: (B) = 3. Czy (A) jest podzielna przez (B)? Nie. Przyrost (B) o +1: (B) = 4. Czy (A) jest podzielna przez (B)? Nie. Przyrost (B) o +1: (B) = 5. Czy (A) jest podzielny przez (B)? Tak. (35/5 = 7). Największy dzielnik, jaki znaleźliśmy poprzednio, jest przechowywany w (C). (C) jest obecnie 3,5 jest większy niż 3, więc aktualizujemy (C) = 5. Aktualizujemy (A) = 7. Resetujemy (B) = 2.

Następnie powtarzamy proces dla (A), ale będziemy po prostu kontynuować inkrementację (B) aż do (B) = (A), ponieważ 7 jest liczbą pierwszą i nie ma dzielników innych niż ona sama i 1. (Mogliśmy już zatrzymaj się, gdy (B)> ((A)/2), ponieważ nie możesz mieć dzielników całkowitych większych niż połowa liczby - najmniejszy możliwy dzielnik (inny niż 1) dowolnej liczby to 2!)

Tak więc punkt, który zwracamy (A) = 7.

Spróbuj zrobić kilka z nich ręcznie, a dostaniesz powiesić idei