<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://www.algopedia.ro/wiki/index.php?action=history&amp;feed=atom&amp;title=Clasa_a_IX-a_lec%C8%9Bia_25</id>
	<title>Clasa a IX-a lecția 25 - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://www.algopedia.ro/wiki/index.php?action=history&amp;feed=atom&amp;title=Clasa_a_IX-a_lec%C8%9Bia_25"/>
	<link rel="alternate" type="text/html" href="https://www.algopedia.ro/wiki/index.php?title=Clasa_a_IX-a_lec%C8%9Bia_25&amp;action=history"/>
	<updated>2026-04-13T02:15:07Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.44.2</generator>
	<entry>
		<id>https://www.algopedia.ro/wiki/index.php?title=Clasa_a_IX-a_lec%C8%9Bia_25&amp;diff=18025&amp;oldid=prev</id>
		<title>Bella: /* Utilizarea Ciurului lui Eratostene */</title>
		<link rel="alternate" type="text/html" href="https://www.algopedia.ro/wiki/index.php?title=Clasa_a_IX-a_lec%C8%9Bia_25&amp;diff=18025&amp;oldid=prev"/>
		<updated>2020-12-04T07:26:37Z</updated>

		<summary type="html">&lt;p&gt;&lt;span class=&quot;autocomment&quot;&gt;Utilizarea Ciurului lui Eratostene&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;== Ciurul lui Eratostene ==&lt;br /&gt;
Eratostene a fost un matematician, geograf, poet, astronom și muzician grec. El a trăit între anii 276 și 195 î.Hr. El a inventat cuvîntul &amp;quot;geografie&amp;quot; în greacă, a inventat un sistem de latitudine și longitudine. A fost primul om care a calculat circumferința pămîntului, a calculat înclinația axei de rotație a pămîntului, a creat conceptul de an bisect, și zi bisectă. Tot el a creat prima hartă a lumii, incluzînd paralele și meridiane.&lt;br /&gt;
&lt;br /&gt;
Eratostene a inventat un algoritm foarte eficient de calcul al tuturor numerelor prime pînă la un număr dat. Acest algoritm se studiază la matematică. El procedează astfel: &lt;br /&gt;
&lt;br /&gt;
# &amp;lt;nowiki&amp;gt;Creează o listă a întregilor consecutivi de la 2 la n: [2, 3, 4, ..., n].&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
# Caută primul număr netăiat din listă (inițial nici un număr nu e tăiat). Fie p acel număr.&lt;br /&gt;
# Mergi din p în p prin listă, începînd cu 2*p și taie toate numerele întîlnite (unele vor fi deja tăiate)&lt;br /&gt;
# Reia de la pasul 2, pînă ce depășim n.&lt;br /&gt;
&lt;br /&gt;
În final numerele rămase netăiate sînt prime.&lt;br /&gt;
&lt;br /&gt;
Cum implementăm acest algoritm, care la origine se executa manual, cu hîrtie și creion? Pentru a simula tăierea numerelor vom folosi un vector de frecvență, &amp;lt;tt&amp;gt;ciur&amp;lt;/tt&amp;gt;, care pentru fiecare număr între &amp;lt;tt&amp;gt;2&amp;lt;/tt&amp;gt; și &amp;lt;tt&amp;gt;n&amp;lt;/tt&amp;gt; ne va spune dacă este tăiat sau nu. Inițial vectorul &amp;lt;tt&amp;gt;ciur&amp;lt;/tt&amp;gt; va fi inițializat cu zero, care semnifică că toate numerele sînt prime, iar pe măsură ce tăiem numere, ele vor fi marcate cu unu. În final &amp;lt;tt&amp;gt;&amp;lt;nowiki&amp;gt;ciur[x]&amp;lt;/nowiki&amp;gt;&amp;lt;/tt&amp;gt; va fi zero dacă numărul este prim, sau unu în caz contrar. Deoarece elementele lui &amp;lt;tt&amp;gt;ciur&amp;lt;/tt&amp;gt; sînt zero sau unu nu are rost să folosim întregi pentru ele, ci vom folosi caractere, văzute ca numere mici. Să ne reamintim că un caracter ocupă un octet (opt biți), pe cînd un întreg ocupă 4 octeți (32 de biți). Astfel, memoria folosită va fi de patru ori mai mică. &amp;#039;&amp;#039;(Vom vedea, în viitor, că memoria se poate reduce în continuare dacă ținem doar un bit pe element.)&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Iată implementarea acestei idei. Programul următor calculează vectorul ciur pentru numerele pînă la &amp;lt;tt&amp;gt;n&amp;lt;/tt&amp;gt;, cu &amp;lt;tt&amp;gt;n&amp;lt;/tt&amp;gt; maxim două milioane:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;char ciur[2000000];&lt;br /&gt;
...&lt;br /&gt;
fscanf( fin, &amp;quot;%d&amp;quot;, &amp;amp;n );&lt;br /&gt;
for ( d = 2; d &amp;lt; n; d++ )&lt;br /&gt;
  if ( ciur[d] == 0 ) // daca d este prim&lt;br /&gt;
    for ( i = d + d; i &amp;lt;= n; i = i + d ) // vom marca numerele din d in d&lt;br /&gt;
      ciur[i] = 1;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Programul se poate optimiza dacă facem următoarele observații:&lt;br /&gt;
&lt;br /&gt;
# În a doua buclă &amp;lt;tt&amp;gt;for&amp;lt;/tt&amp;gt; variabila &amp;lt;tt&amp;gt;i&amp;lt;/tt&amp;gt; ia valorile &amp;lt;tt&amp;gt;2∙d, 3∙d, 4∙d, ..., k∙d&amp;lt;/tt&amp;gt;. Pentru &amp;lt;tt&amp;gt;&amp;lt;nowiki&amp;gt;k &amp;lt; d&amp;lt;/nowiki&amp;gt;&amp;lt;/tt&amp;gt; toate valorile de forma &amp;lt;tt&amp;gt;k∙d&amp;lt;/tt&amp;gt; au fost deja tăiate de valorile &amp;lt;tt&amp;gt;k&amp;lt;/tt&amp;gt; anterioare, drept pentru care nu are rost să le mai parcurgem. Putem să pornim cu &amp;lt;tt&amp;gt;i&amp;lt;/tt&amp;gt; de la &amp;lt;tt&amp;gt;d∙d&amp;lt;/tt&amp;gt;.&lt;br /&gt;
# Conform observației anterioare &amp;lt;tt&amp;gt;i&amp;lt;/tt&amp;gt; pornește de la &amp;lt;tt&amp;gt;d∙d&amp;lt;/tt&amp;gt;. De aceea nu are rost să mergem cu &amp;lt;tt&amp;gt;d&amp;lt;/tt&amp;gt; mai departe de &amp;lt;tt&amp;gt;sqrt(n)&amp;lt;/tt&amp;gt;, deoarece nu vom mai găsi &amp;lt;tt&amp;gt;i&amp;lt;/tt&amp;gt; astfel încît &amp;lt;tt&amp;gt;i ≤ n&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Iată implementarea optimizată, bazată pe aceste două observații:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;char ciur[2000000];&lt;br /&gt;
...&lt;br /&gt;
fscanf( fin, &amp;quot;%d&amp;quot;, &amp;amp;n );&lt;br /&gt;
for ( d = 2; d * d &amp;lt;= n; d++ )&lt;br /&gt;
  if ( ciur[d] == 0 ) // daca d este prim&lt;br /&gt;
    for ( i = d * d; i &amp;lt;= n; i = i + d ) // vom marca numerele din d in d&lt;br /&gt;
      ciur[i] = 1;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
= Lectie = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Varianta usor optimizata ===&lt;br /&gt;
Pentru un numar d prim, vom marca toti multiplii acestuia, nepari&lt;br /&gt;
Ex: pentru d = 7, marcam multiplii: 7*7, 7*9, 7*11...sarind peste 7*8, 7*10...&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;char ciur[2000000];&lt;br /&gt;
...&lt;br /&gt;
fscanf( fin, &amp;quot;%d&amp;quot;, &amp;amp;n );&lt;br /&gt;
for ( d = 4; d &amp;lt;= n; d += 2 )&lt;br /&gt;
  ciur[d] = 1;&lt;br /&gt;
for ( d = 3; d * d &amp;lt;= n; d+= 2 )&lt;br /&gt;
  if ( ciur[d] == 0 ) // daca d este prim&lt;br /&gt;
    for ( i = d * d; i &amp;lt;= n; i = i + 2 * d ) // vom marca numerele din 2d in 2d&lt;br /&gt;
      ciur[i] = 1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Putem de asemenea sa optimizam si memoria folosita, pastrand valorile ciurului doar pentru elementele impare.&lt;br /&gt;
 &lt;br /&gt;
ciur[1] va retine daca 3 e prim&lt;br /&gt;
ciur[2] va retine daca 5 e prim&lt;br /&gt;
ciur[3] va retine daca 7 e prim&lt;br /&gt;
ciur[d/2] va retine daca d e prim&lt;br /&gt;
Adica:&lt;br /&gt;
ciur[k] va retine daca 2k + 1 e prim&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
char ciur[2000000];&lt;br /&gt;
for ( d = 3; d * d &amp;lt;= n; d+= 2 )&lt;br /&gt;
  if ( ciur[d/2] == 0 ) // daca d este prim&lt;br /&gt;
    for ( i = d * d; i &amp;lt;= n; i = i + 2 * d ) &lt;br /&gt;
      ciur[i/2] = 1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nu uitați:&lt;br /&gt;
* Vectorul &amp;lt;tt&amp;gt;ciur[]&amp;lt;/tt&amp;gt; este de tip caracter și nu întreg!&lt;br /&gt;
* În final vectorul &amp;lt;tt&amp;gt;ciur[i]&amp;lt;/tt&amp;gt; este &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; dacă numărul este prim sau &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; în caz contrar.&lt;br /&gt;
&lt;br /&gt;
Complexitate? Matematica este complexă, dar rețineți că metoda este aproximativ &amp;#039;&amp;#039;O(n)&amp;#039;&amp;#039; pentru valorile lui n cu care vom lucra noi. Pentru cei interesați, complexitatea este de fapt &amp;#039;&amp;#039;O(n∙log&amp;amp;nbsp;log&amp;amp;nbsp;n)&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
== Utilizarea Ciurului lui Eratostene ==&lt;br /&gt;
===Calcului numarului de divizori ===&lt;br /&gt;
Putem modifica modul de parcurgere al vectorului pentru a calcula numarul de divizori pentru numerele de la 1 la n:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
int num_div[2000000];&lt;br /&gt;
...&lt;br /&gt;
fscanf( fin, &amp;quot;%d&amp;quot;, &amp;amp;n );&lt;br /&gt;
for ( d = 1; d &amp;lt;= n; d++ )&lt;br /&gt;
  for ( i = d; i &amp;lt;= n; i = i + d )&lt;br /&gt;
    num_div[i]++;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
De asemenea putem calcula similar suma divizorilor pentru numerele de la 1 la n:&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
int sum_div[2000000];&lt;br /&gt;
...&lt;br /&gt;
fscanf( fin, &amp;quot;%d&amp;quot;, &amp;amp;n );&lt;br /&gt;
for ( d = 1; d &amp;lt;= n; d++ )&lt;br /&gt;
  for ( i = d; i &amp;lt;= n; i = i + d )&lt;br /&gt;
    sum_div[i] = sum_div[i] + d;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Construirea unui vector de numere prime ( Compactarea ciurului ) ==&lt;br /&gt;
Dorim sa contruim un vector de numere prime mai mici sau egale cu o valoare data VMAX. Ne vom folosi deci de ciurul lui Eratostene pentru a determina care numere sunt prime pana la VMAX. Vom ignora numerele pare atunci cand marchez numerele neprime, neaccesand nicioadata aceste pozitii. Vom marca penru un divizor d divizorii acestuia impari: d * d, d*(d+2), sarind peste elementele d*(d+1), d*(d+3) acestea fiind numere pare.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#define VMAX 1000000&lt;br /&gt;
char ciur[VMAX+1] = {0}; &lt;br /&gt;
int prime[300000];  // dimensiunea vectorului este data de numarul de numere prime pe care le-as putea gasi pena la VMAX&lt;br /&gt;
&lt;br /&gt;
int main(){&lt;br /&gt;
  ................. &lt;br /&gt;
  // marcam in ciur numerele impare prime&lt;br /&gt;
  for(int d = 3; d * d &amp;lt;= VMAX; d +=2 )&lt;br /&gt;
    if( ciur[d] == 0 )                                                 &lt;br /&gt;
      for(int i = d * d; i&amp;lt;= VMAX; i = i + 2 * d )   &lt;br /&gt;
        ciur[i] = 1;&lt;br /&gt;
  // punem nr 2 in vectorul de numere prime, fiind singurul nr par prim&lt;br /&gt;
  prime[0] = 2; &lt;br /&gt;
  // parcurgem ciurul doar pe pozitiile impare si construim vectorul de numere prime&lt;br /&gt;
  k = 1;&lt;br /&gt;
  for( d = 3; d &amp;lt;= VMAX; d += 2 )&lt;br /&gt;
    if( ciur[d] == 0 ) &lt;br /&gt;
       prime[k++] = d;&lt;br /&gt;
...................&lt;br /&gt;
} &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#define VMAX 1000000&lt;br /&gt;
&lt;br /&gt;
char ciur[VMAX] = {0}; &lt;br /&gt;
int prime[300000];         &lt;br /&gt;
&lt;br /&gt;
  v[0] = 2; k = 1;&lt;br /&gt;
  for(d = 3; d &amp;lt;= 1000000; d +=2 )&lt;br /&gt;
    if( ciur[d] == 0 ){                                       // daca d e prim&lt;br /&gt;
      prime[k++] = d;                                         // pun val d in vectorul v&lt;br /&gt;
      for(long long i = 1LL * d * d; i&amp;lt;= 1000000; i=i+2*d )   // marchez ca neprime&lt;br /&gt;
        ciur[i] = 1;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
https://infoarena.ro/problema/divprim&lt;br /&gt;
&lt;br /&gt;
= Temă  =&lt;br /&gt;
== Tema Teorie == &lt;br /&gt;
Tema 23 de pe pbinfo&lt;br /&gt;
&lt;br /&gt;
== Tema Laborator == &lt;br /&gt;
Rezolvati problemele din runda de pe varena:&lt;br /&gt;
* [http://varena.ro/runda/c2_9 Tema 24] &lt;br /&gt;
** [http://varena.ro/problema/apropiate apropiate]&lt;br /&gt;
** [http://varena.ro/problema/apropiate1 apropiate1]&lt;br /&gt;
** [http://varena.ro/problema/extraprime extraprime]&lt;br /&gt;
** [http://varena.ro/problema/prime prime]&lt;br /&gt;
** [http://varena.ro/problema/kdiv kdiv]&lt;br /&gt;
&lt;br /&gt;
=== Ciur ===&lt;br /&gt;
* [http://varena.ro/problema/prime prime], Ioana Bica [http://isa.algopedia.ro/wiki/index.php/prime Rez]&lt;br /&gt;
* [http://campion.edu.ro/arhiva/index.php?page=problem&amp;amp;action=view&amp;amp;id=1176 bileprime] campion 2010, (inca nu e pusa pe varena) [http://isa.algopedia.ro/wiki/index.php/bileprime Rez]&lt;br /&gt;
* [http://varena.ro/problema/paisprezece paisprezece] [http://isa.algopedia.ro/wiki/index.php/paisprezece Rez]&lt;br /&gt;
* [https://www.pbinfo.ro/?pagina=detalii-evaluare&amp;amp;id=7712114 extraprime]&lt;br /&gt;
=== Ciur, Compactare Ciur ===&lt;br /&gt;
* [http://campion.edu.ro/arhiva/index.php?page=problem&amp;amp;action=view&amp;amp;id=365 prime], campion2005 (inca nu e pusa pe varena)&lt;br /&gt;
* [http://varena.ro/problema/sprime sprime], XOR 2015 clasa a 9 a&lt;br /&gt;
&lt;br /&gt;
=== Ciur modificat === &lt;br /&gt;
* [http://varena.ro/problema/kdiv kdiv] aplicație a ciurului lui Eratostene - folosim ciurul pentru a memora pentru fiecare numar cati divizori primi are fiecare numar&lt;br /&gt;
* [http://varena.ro/problema/intervale intervale] aplicație a ciurului lui Eratostene - folosim ciurul pentru a memora pentru fiecare numar cati divizori primi are fiecare numar + sume partiale&lt;br /&gt;
* Prime1 - pbinfo oni 2017 clasa a v-a ca aplicație a ciurului lui Eratostene; folosim ciurul pentru a marca ce numere sunt si prime si in sirul lui fibbonacci&lt;br /&gt;
&lt;br /&gt;
Optional&lt;br /&gt;
* [http://varena.ro/problema/prim prim] dată la ONI 2003 clasa a 5&amp;lt;sup&amp;gt;a&amp;lt;/sup&amp;gt;&lt;br /&gt;
* [http://varena.ro/problema/cub1 cub1] dată la ONI 2002 clasa a 5&amp;lt;sup&amp;gt;a&amp;lt;/sup&amp;gt;&lt;/div&gt;</summary>
		<author><name>Bella</name></author>
	</entry>
</feed>