უსგ და ერატოსთენეს საცერი

წილადების შეკვეცა, განმეორებადი განრიგების დამთხვევა, რიცხვების დაშლა, ჰეშირება მარტივი რიცხვებით: ორი ძველბერძნული ალგორითმი დღესაც ამ საქმეს აკეთებს ყველა ოლიმპიადაზე და ბევრ რეალურ კოდში.

საშუალო⏱ 12 წთ
01

ისწავლე

იდეა, მექანიზმი და ფასი.

01ევკლიდეს ალგორითმი

უდიდესი საერთო გამყოფი უსგ(a, b) ის უდიდესი რიცხვია, რომელიც ორივეს ყოფს. ყველა კანდიდატის ცდა ნელია. ევკლიდემ შენიშნა, რომ a-სა და b-ს ყოველი საერთო გამყოფი a mod b-საც ყოფს, რადგან a mod b = a − q·b. ამიტომ

gcd(a, b) = gcd(b, a mod b) და gcd(a, 0) = a.

84-ისა და 60-ისთვის: (84, 60) → (60, 24) → (24, 12) → (12, 0), ანუ პასუხი 12-ია სამი გაყოფის შემდეგ. კოდში ერთი სტრიქონია: while (b) { t = a % b; a = b; b = t; }.

უსგ-ს ცოდნით უმცირესი საერთო ჯერადიც მარტივად მიიღება: lcm(a, b) = a / gcd(a, b) * b. ჯერ გაყავი, რომ შუალედური მნიშვნელობა არ გადაივსოს.

(84, 60)84 = 1·60 + 24(60, 24)60 = 2·24 + 12(24, 12)24 = 2·12 + 0(12, 0)უსგ = 12gcd(a, b) = gcd(b, a mod b)

02რატომ არის ევკლიდე ასეთი სწრაფი

ორი ბიჯის შემდეგ დიდი რიცხვი სულ მცირე ორჯერ მცირდება. თუ b ≤ a/2, მაშინ a mod b < b ≤ a/2. თუ b > a/2, მაშინ a mod b = a − b < a/2. ორივე შემთხვევაში წყვილი სწრაფად მცირდება, ამიტომ ევკლიდეს სჭირდება O(log min(a, b)) ბიჯი: 64-ბიტიანი რიცხვებისთვისაც დაახლოებით 90 გაყოფა.

სიმარტივის შემოწმებასაც მსგავსი მოკლე გზა აქვს. იმის გასარკვევად, მარტივია თუ არა n, საკმარისია გამყოფები √n-მდე სცადო, რადგან გამყოფები წყვილებად მოდის d · (n/d) და წყვილიდან ერთი ყოველთვის ≤ √n. ეს გვაძლევს O(√n) შემოწმებას, რაც ერთი რიცხვისთვის დაახლოებით 10^12-მდე საკმარისია.

მაგრამ თუ ყველა მარტივი რიცხვი გჭირდება n-მდე, თითოეულის ცალკე შემოწმება O(n√n) ჯდება. საცერი გაცილებით უკეთესია.

36-ის გამყოფების წყვილები≤ √36 = 6≥ 611 · 36 = 363622 · 18 = 361833 · 12 = 361244 · 9 = 36966 · 6 = 366ყოველ წყვილში ერთი გამყოფი ≤ √n, ამიტომ საკმარისია √n-მდე შემოწმება

03ერატოსთენეს საცერი

ჩაწერე 2..n და ყველა მონიშნე „შესაძლოა მარტივად“. p-ს ზემოთ მივყვეთ. თუ p ჯერ კიდევ გადაუხაზავია, ის მარტივია, რადგან მასზე მცირე არცერთი მარტივი არ ყოფს. შემდეგ ვხაზავთ მის ჯერადებს. ორი დეტალი ხდის სწრაფს:

  • ხაზვას ვიწყებთ p²-დან: უფრო მცირე ჯერადები, მაგ. 2p და 3p, 2-მა და 3-მა უკვე გადახაზეს
  • ვჩერდებით, როცა p² > n: ყოველ შედგენილ რიცხვს ≤ n აქვს მარტივი გამყოფი ≤ √n, ამიტომ დარჩენილი ყველა მარტივია

for p in 2..: if p*p > n break; if is[p]: for m = p*p; m <= n; m += p: is[m] = false

სრული შრომა მარტივებზე n/2 + n/3 + n/5 + … ჯამია, რაც O(n log log n)-ია: პრაქტიკულად წრფივი. საცერი 10^7-მდე წამზე გაცილებით სწრაფად სრულდება და თითო რიცხვზე ერთ ბაიტს (ან ერთ ბიტს) მოითხოვს.

12345678910111213141516171819202122232425262728293031323334353637383940მარტივიგადახაზა:235p-ს ჯერადებს ვხაზავთ p²-დან
ყოველი შედგენილი რიცხვი იმ პირველი მარტივის ფერითაა, რომელმაც გადახაზა. n = 40-ისთვის საკმარისია 2, 3 და 5, რადგან 7² = 49 > 40.

04ჩვეულებრივი საცრის მიღმა

პატარა გაუმჯობესება საცერს გაცილებით სასარგებლოს ხდის. ბულის მნიშვნელობის ნაცვლად შეინახე spf[m], უმცირესი მარტივი გამყოფი, როცა m პირველად გადაიხაზება. შემდეგ ნებისმიერი m ≤ n დაიშლება O(log m)-ში: განმეორებით გაყავი spf[m]-ზე.

ტიპური გამოყენებები:

  • ბევრი რიცხვის გამყოფების დათვლა (დაშალე, შემდეგ გადაამრავლე ხარისხები + 1)
  • ურთიერთმარტივობის შემოწმება: gcd(a, b) == 1
  • წილადის შეკვეცა: ორივე ნაწილი გაყავი მათ უსგ-ზე

ხაფანგები: 1 არც მარტივია და არც შედგენილი, ამიტომ ცალკე მონიშნე. გამოყავი n + 1 ელემენტი. დიდი n-ისთვის p * p 64-ბიტში გამოთვალე, რომ არ გადაივსოს.

ფასი ერთი შეხედვით

უსგ (ევკლიდე)O(log min(a,b))
სიმარტივის შემოწმება გაყოფითO(√n)
საცერი: ყველა მარტივი n-მდეO(n log log n)
m-ის დაშლა spf საცრითO(log m)

დაიმახსოვრე

  1. უსგ(a, b) = უსგ(b, a mod b), სანამ b 0 არ გახდება; სჭირდება მხოლოდ O(log) ბიჯი, ხოლო უსჯ = a / უსგ · b.
  2. გამყოფები √n-ის გარშემო წყვილებად მოდის, ამიტომ სიმარტივის შემოწმება და საცერი √n-ზე შეიძლება გაჩერდეს.
  3. საცერი ჯერადებს p²-დან ხაზავს და ყველა მარტივ რიცხვს n-მდე O(n log log n)-ში პოულობს.
02

ითამაშე

გაიარე ალგორითმი ბიჯ-ბიჯ, მერე სცადე შენს მონაცემებზე.

👀 რას უყურო: ჯერ უყურე, როგორ მცირდება (a, b) (უსგ, 0)-მდე. შემდეგ საცერში შენიშნე, რომ ყოველი ახალი მარტივი ხაზვას p²-დან იწყებს და რომ გაშვება n-მდე მისვლამდე ბევრად ადრე ჩერდება.

ინტერაქტიული ვიზუალიზატორიაქ დააწკაპე, მერე space ← →
✎ შენი მონაცემებიn: 10–100. a, b: 1–100000, ან ორივე ცარიელი დატოვე, მხოლოდ საცრისთვის.

ევკლიდეს ალგორითმი

aba mod b
8460·

ერატოსთენეს საცერი, 2..60

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
მარტივიახლახან გადახაზულიშედგენილი (გადახაზული)ჯერ უცნობიმიმდინარე p
უსგ(84, 60): a-სა და b-ს ყოველი საერთო გამყოფი a mod b-საც ყოფს, ამიტომ (a, b) შეგვიძლია შევცვალოთ (b, a mod b)-ით და პასუხი არ შეიცვლება.

ფსევდოკოდი

 1 gcd(a, b): while b != 0: 2   (a, b) = (b, a mod b) 3   return a 4 is_prime[2..n] = true 5 for p = 2; p * p <= n; p++: 6   if is_prime[p]:                 // p is prime 7     for m = p*p; m <= n; m += p: is_prime[m] = false 8 every number still marked true is prime
1 / 1
03

შეამოწმე

სამი კითხვა. აირჩიე პასუხი და ნახე ახსნა.

№1

ევკლიდე (48, 18)-ზე: რომელი წყვილი მოდის უშუალოდ (48, 18)-ის შემდეგ?

№2

საცერში n = 100-მდე რომელია ბოლო p, რომლის ჯერადებსაც ვხაზავთ?

№3

რატომ იწყებს საცერი p-ს ჯერადების ხაზვას p²-დან და არა 2p-დან?

04

ივარჯიშე

რეალური ამოცანები გასამყარებლად, მარტივიდან რთულისკენ.