Prosti brojevi
Je li broj prost?
Kako odrediti je li neki broj prost? Možemo jednostavno proći po svim brojevima između i te ako nije djeljiv niti s jednim od tih brojeva onda je prost. Složenost ovog postupka je očito .
Postoji li brži načina da odredimo prostost broja? Naravno. Primijetimo da nije nužno gledati brojeve veće od . Zašto? Neka je djeljiv s nekim brojem , tada je nužno djeljiv i s brojem . Jedan od brojeva i nužno je manji ili jednak . Razmislite zašto.
Sada više ne moramo provjeravati , već samo brojeva čime smo složenost spustili na . Tu složenost možemo dodatno prepoloviti ako gledamo djeljivost samo s neparnim brojevima, a broj provjerimo samo jednom, no to često nije nužno.
//funkcija vraća true ako je broj prost odnosno false ako nije
bool isPrime(int x){
//1 nije prost
if(x == 1) return false;
for(int i = 2; i <= sqrt(x); i++) if(x % i == 0) return false;
return true;
}
Eratostenovo sito
Zanimaju nas svi brojevi manji od koji su prosti. Naravno možemo primijeniti funkciju napisanu gore i za svaki broj provjeriti je li prost. Složenost tog postupka bila bi . No postoji još jedan način određivanja prostih brojeva koji ima neka korisna svojstva. Riječ je o Eratostenovom situ(engl. sieve of Eratosthenes). Postupak je sljedeći:
- Svi brojevi su prosti
- Krećemo od 2 i svaki višekratnik tog broja označimo kao ne prost
- Točku 2 ponavljamo po redu za svaki broj koji je i dalje označen kao prost
const int MAXN = 1e5 + 5;
bool prosti[MAXN];
void eratosten(int n){
//označimo sve višekratnike od 2 kao ne proste
for(int i = 4; i < n; i += 2)
prosti[i] = false;
for(int i = 3; i < n; i += 2){
if(!prosti[i]) continue;
for(int j = i + i; j < n; j += i)
prosti[i] = false;
}
}
int main(){
memset(prosti, true, sizeof prosti);
eratosten(MAXN);
//sada u poju prosti imamo označene sve proste brojeve
}
Složenost ovog algoritma je , što je jednako , može se pokazati da je ova suma reda , a ukupna složenost ovog algoritma je , no to ovdje nećemo dokazivati, ono što također možete primijetiti je da će se u sumi nalaziti samo prosti brojevi pa se naša složenost smanjuje na . Možete primijetiti da je član jako mali i za potrebe natjecateljskog programiranje ne prelazi pa ga je gotovo moguće zanemariti, ipak ako je ograničenje gusto ili je time limit malen, treba imati na umu da postoji.
Rastav broja na proste faktore
Eratostenovo sito moguće je prilagoditi kako bi pomoću njega mogli saznati rastav broja na proste faktore. Umjesto da zapisujemo je li broj prost ili ne, u polje ćemo zapisivati koji prosti broj je poništio prostost tog broja.
const int MAXN = 1e5 + 5;
int prosti[MAXN];
void eratosten(int n){
for(int i = 4; i < n; i += 2)
prosti[i] = 2;
for(int i = 3; i < n; i += 2){
if(prosti[i] != 0) continue;
for(int j = i + i; j < n; j += i)
if(prosti[j] == 0) prosti[j] = i;
}
}
void ispisi_rastav(int x){
while(prosti[x] != 0){
cout << prosti[x] << ' ';
x = x/prosti[x];
}
cout << x;
}
int main(){
memset(prosti, 0, sizeof prosti);
eratosten(MAXN);
int n;
cin >> n;
ispisi_rastav(n);
}
Na sljedeći načina dobivamo ispis rastava broja na proste faktore:
- Ispiši broj zapisan na -tom mjestu
- Podijeli s ispisanim brojem
- Ako novi broj nije prost vrati se na , inače ispiši taj broj
Ovim postupkom u složenosti možemo dobiti rastav broja na proste faktore. Broj prostih faktora od nikad neće biti veći od , razmislite zašto, pa će tako složenost biti maksimalno .
Dokaz. Uzmimo u obzir sve brojeve koji imaju prostih faktora, koji je najmanji od njih? To je očito , a rastav na proste faktore sastoji se od dvojki. Za najmanji koji ima prostih faktora vrijedi jer je , a znamo da vrijedi za sve pa prema tome uistinu je gornja granica za broj prostih faktora nekog broja.