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

Algoritm EFICIENT din punct de vedere al timpului de executie (eventual program C++) pentru a calcula suma cifrelor tuturo
numerelor de la 1 la n (unde n<=2.000.000.000). Am nevoie de el pentru rezolvarea unei probleme si algoritmul clasic (brut) consuma foarte mult timp.
Multumesc mult pentru ajutor!
ATENTIE!
E a treia oara cand postez intrebarea. Cei care nu stiu raspunsul sa nu se mai bage.


JohnAndrew: faci n/10
JohnAndrew: apoi iei cu mod nr 2
JohnAndrew: si k tau o sa fie 1 acum
JohnAndrew: o sa ai 2*10
JohnAndrew: f(20) cu formula
JohnAndrew: n=n/10
JohnAndrew: loop III) iei ultima cifra
JohnAndrew: 1 , k=2 o sa ai f(100)
JohnAndrew: si la fiecare loop ai un sum+=f( ce obtii )
JohnAndrew: ok , am reusit sa il fac

Răspunsuri la întrebare

Răspuns de blindseeker90
2
#include <iostream>
#include <cmath>
#include <time.h>
using namespace std;

int nr_cifre(int n){
int nr=0;
while(n>0){
nr++;
n=n/10;
}
return nr;
}
double s=0;
double suma_cifre(int n){
int a[12],i,d,p,c;
;
if(n<10){
return n*(n+1)/2;
}
//numarul d reprezinta nr cifre-1, adica intervalul acela 1-999
d=nr_cifre(n)-1;
a[0]=0;
a[1]=45;
for(i=2;i<=d;i++){
a[i]=a[i-1]+45*(int)pow(10,i-1);
}
p=(int)pow(10,d);
//c este prima cifra din sir
c=n/p;

//mai intai adunam intervalul acela 1-9999 inmultit cu prima cifra
s=s+c*a[d];
//si acum trebuie sa adunam si numerele de la 1 pana la c
//daca de exemplu am 5678, 5*(1-999) ar presupune ca prima cifra e mereu 1
//dar de fapt poate sa fie de la 1 la c
s=s+p*(c-1)*c/2;
//al treilea termen trebuie sa adune cifra c pentru toate numerele din intervalul c0000-n
//deci pentru 5678 ar fi de la 5000 pana la 5678 ca sa numaram aparitiile lui 5
//in formula de mai jos am 1+ pentru ca trebuie sa adaug si termenul 0, adica 5000
s=s+c*(1+n%p);
//si acum am luat totul in calcul, facem din nou suma respectiva
s=s+suma_cifre(n%p);
//algoritmul se va termina atunci cand ajungi la sub 10 si se va activa returnul de mai sus
return s;
}

//-----------------------------------------------
int suma_cifre_nr(int n){
double s=0;
while(n>0){
s=s+n%10;
n=n/10;
}
return s;
}
//metoda de calcul brut clasica
double suma_cifre_calc_brut(int n){
int i;
double suma=0;
for(i=1;i<=n;i++){
suma=suma+suma_cifre_nr(i);
}
return s;
}


int main(){

int n;
double time1,time2;
cin>>n;
clock_t start=clock();
cout<<"Suma cifre: "<<suma_cifre(n)<<endl;
clock_t end=clock();
time1=((double)(end-start)/CLOCKS_PER_SEC)*100000;
start=clock();
cout<<"Suma cifre brut: "<<suma_cifre_calc_brut(n)<<endl;
end=clock();
time2=((double)(end-start)/CLOCKS_PER_SEC)*100000;
cout<<"Timp 1: "<<time1<<" Time 2: "<<time2<<endl;
cout<<"Algoritmul 1 este de "<<time2/time1<<" mai rapid decat algoritm brut";

return 0;
}

ionutg38: Sper sa nu va suparati pe mine :(
ionutg38: Dar m-am chinuit singur si ma durea capu'. Am crezut ca cineva l-a folosit deja
ionutg38: Daca vreti, mai postez odata si pot sa dau si toate punctele mele, pentru ca nu ma intereseaza punctele ci sa ajut si sa fiu ajutat
blindseeker90: E frustrant din cauza faptului ca suntem foarte aproape. Eu valoarea aceea de 15249 o obtin intr-un calcul intermediar, dar la final mai face inca o data suma in plus si imi da valoarea aceea. Nu stiu cum sa transmit parametri de la functie catre ea insasi, cred ca acolo mi se rupe filmul
ionutg38: Am inteles.
blindseeker90: Am mai facut acum o modificare la program la intrebarea precendenta. Acum merge pentru 1176. Sa-mi spui daca iti da erori pentru altele
blindseeker90: Am eliminat complet variabila s din recursivitate, fac direct return de suma termenilor la fiecare iteratie
ionutg38: Unde ai postat raspunsul?
blindseeker90: La cea precedenta, ca la asta nu mai am cum sa editez. Cea la care anuntai tu cu ATENTIE ca astepti raspuns de la mine, cea la care mi-ai dat 5 stele
blindseeker90: Acesta e codul pentru nr cifre acum: double suma_cifre(int n){
int i,d,p,c,k=0;

if(n<10){
return n*(n+1)/2;
}
//numarul d reprezinta nr cifre-1, adica intervalul acela 1-999
d=nr_cifre(n)-1;
int a[12];
a[0]=0;
a[1]=45;
for(i=2;i<=d;i++){
a[i]=a[i-1]*10+45*ceil(pow(10,i-1));
}
p=ceil(pow(10,d));
//c este prima cifra din sir
c=n/p;
return c*a[d]+p*(c-1)*c/2+c*(1+n%p)+suma_cifre(n%p);

}
Alte întrebări interesante