Informatică, întrebare adresată de imthebestprogrammer, 9 ani în urmă

Cerința
Se dă un număr natural n. Să se determine numărul din intervalul [1,n] care are număr maxim de divizori. Dacă există mai multe asemenea numere, se va afișa cel mai mic dintre ele.

Date de intrare
Programul citește de la tastatură numărul n.

Date de ieşire
Programul va afișa pe ecran valoarea cerută.

Restricții și precizări
0 < n <= 100.000



Exemplu
Intrare

20
Ieșire

12
Explicații:
12, 18 şi 20 au număr maxim de divizori, dar 12 este cel mai mic.
-------Ideea mea------
Ma gandeam sa determin nr de divizori ai ultimului numar(20) si dupa sa scad cate 1 (19 18 17 16) si sa verifiic daca au acelasi nr de divizori daca un numar are atunci va primi min dar nu stiu cum ar trebuii sa fac programul sa se opreasca acolo(val 12).Nu cred ca ideea mea este foarte buna avand in vedere timpul rularii programului.
Va rog daca se poate sa imi rezolvati problema in orice mod considerati dv ca algoritmul este bun dar daca se poate sa imi si explicati ce se intampla in cod.
Multumesc!!!


Răspunsuri la întrebare

Răspuns de ated
3
Solutia asta are 100p. Ceea ce fac in cod e destul de simplu: iau numere de la 1 la n, daca numarul lor de divizori e mai mare (nu "mai mare sau egal" pentru ca vrem numarul MINIM cu un numar maxim de divizori -  "se va afișa cel mai mic dintre ele.") decat maximul precedent modific maximul si continui.
Ca sa fie mai rapid totul, nu calculez numarul de divizori pana la n sau n/2, ci pana la sqrt(n), iar asta nu afecteaza comparatiile (pentru ca toate numerele de divizori vor fi mai mici, nu doar cateva). Daca as fi avut nevoie de valoare lor exacta (deci nu doar pentru a verifica daca nrDiv(a) >b) nu as fi facut asa, dar pentru ca nu e nevoie am ales varianta asta ceva mai rapida.

#include <iostream>

using namespace std;

// Numarul de divizori pana la sqrt(n), pentru eficienta
int nrDiv(int n)
{
    int nr = 0;
    for (int i=2; i*i <= n; i++)
        if (n%i == 0)
            nr ++;
    return nr;
}

int main()
{
    /**
     * maxDiv = numarul de divizori maxim
     * maxNr = numarul cu maxDiv divizori, care va fi afisat
     */
    int n, maxDiv = 1, maxNr = 1;
    cin >> n;
    for (int i=1; i<=n; i++)
    {
        // Ca sa nu il calculam de doua ori
        int nr = nrDiv(i);

        if (nr > maxDiv)
        {
            maxDiv = nr;
            maxNr = i;
        }
    }
    cout << maxNr;
    return 0;
}

imthebestprogrammer: Nu am inteles niciodata metoda asta cu cu sqrt de ce nu se pune sqrt n ???,si se pune i*i?
ated: Radicalul dureaza mai mult sa fie calculat decat o inmultire. Daca ridici inecuatia i <= sqrt(n) la patrat o sa iti dea i*i <= n, deci e acelasi lucru, doar ca ceva mai rapid.
imthebestprogrammer: Am inteles !!!!!.Iti multumesc extrem de mult :)
ated: Cu placere :).
Mrincredible: In for unde verifici divizorii trebuie sa ai si un if(i*i == n) nr -- :
Mrincredible: Am gresit nu lua in seama ce am spus
Alte întrebări interesante