Задаци: Елементарне статистике

Алгоритми и програми у програмском језику C: Елементарне статистике.

Факторијел

Прочитај текст задатка.

За одређивање факторијела природног броја \(n\) користимо променљиву faktorijel у којој редом акумулирамо производ бројева од 1 до \(n\).

На почетку вредност променљиве faktorijel поставимо на 1. Након тога, коришћењем петље у којој ћемо бројачкој променљивој \(i\), додељивати редом вредности од 1 до \(n\), у сваком пролазу кроз петљу променљиву faktorijel множити са \(i\).

Предложено решење задатка

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main(void)
{
    int n, f = 1;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
        f *= i;
    printf("%d", f);
    return 0;
}

Степен

Прочитај текст задатка.

Резултат можемо добити ако израчунамо производ \(\underbrace{x\cdot\ldots\cdot x}_n\). Производ серије итеративно можемо израчунати тако што вредност производа иницијализујемо на јединицу, а затим га у сваком кораку петље множимо са наредним елементом серије (у овом случају вредношћу \(x\)).

Предложено решење задатка (1)

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main(void)
{
    double x;
    int n, f = 1;
    scanf("%lf%d", &x, &n);
    double s = 1.0;
    for (int i = 0; i < n; i++)
        s *= x;
    printf("%.5lf", s);
    return 0;
}

Већина језика већ пружа готову функцију или операцију степеновања. У језику C степеновање реалних бројева се врши функцијом pow, декларисаној у заглављу math.h.

Предложено решење задатка (2)

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <math.h>

int main(void)
{
    double x;
    int n, f = 1;
    scanf("%lf%d", &x, &n);    
    printf("%.5lf", pow(x, n));
    return 0;
}

Просек свих бројева до краја улаза

Прочитај текст задатка.

Као што смо већ видели, рачунање просека серије бројева своди се на засебно израчунавање збира и броја елемената серије и њихово дељење (ако су и збир и број цели бројеви, пре дељења је потребно конвертовати их у реални тип).

Видели смо и да се збир серије бројева израчунава тако што се променљива у којој се акумулира збир иницијализује на нулу, а затим се у петљи пролази кроз елементе серије и збир се увећава за текући елемент.

Видели смо и да се број елемената серије одређује тако што се бројачка променљива у којој се тај број акумулира иницијализује на нулу, а затим се у петљи пролази кроз елементе серије и бројач се у сваком кораку увећава за један.

Показано је и како се може организовати петља која учитава све бројеве са стандардног улаза.

Предложено решење задатка

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main(void)
{
    int z = 0, i = 0, n;
    while (scanf("%d", &n) != EOF)
    {
        z += n;
        i++;
    }
    double p = (double)z / (double)i;
    printf("%.5lf", p);
    return 0;
}

Средине

Прочитај текст задатка.

Просечна брзина представља однос укупног пређеног пута и укупног времена трајања пута.

Претпоставимо да је сваки део пута трајао исто време \(t\) (у сатима). Тада је на првом делу пута аутомобил прешао \(v_1\cdot t\) километара, на другом \(v_2\cdot t\) километара, и тако даље, док је на последњем делу прешао \(v_n\cdot t\) километара. Дакле, укупан пређени пут је \((v_1+v_2+\ldots+v_n)\cdot t\) километара. Укупно време је \(n\cdot t\) сати. Зато је просечна брзина једнака \(\frac{(v_1+v_2+\ldots+v_n)\cdot t}{n\cdot t}=\frac{v_1+v_2+\ldots+v_n}{n}\).

Претпоставимо сада да је на сваком делу пута аутомобил прешао исто растојање \(s\) (у километрима). Тада се на првом делу пута кретао \(\frac{s}{v_1}\) сати, на другом \(\frac{s}{v_2}\) сати и тако даље, све до последњег дела где се кретао \(\frac{s}{v_n}\) сати. Дакле, укупни пређени пут је \(n\cdot s\), док је укупно време једнако \(\frac{s}{v_1}+\frac{s}{v_2}+\ldots+\frac{s}{v_n}\). Дакле, просечна брзина једнака је \(\frac{s\cdot n}{\frac{s}{v_1}+\frac{s}{v_2}+\ldots+\frac{s}{v_n}}=\frac{n}{\frac{1}{v_1}+\frac{1}{v_2}+\ldots+\frac{1}{v_n}}\).

Приметимо да се у првом случају просечна брзина израчунава као аритметичка средина појединачних брзина, док се у другом случају израчунава као хармонијска средина појединачних брзина.

Израчунавање аритметичке средине (просечне вредности) свих бројева учитаних са стандардног улаза приказали смо раније. У овом случају радимо са реалним бројевима, па је имплементација још једноставнија јер не морамо да водимо рачуна о конверзији типова. Што се тиче израчунавања хармонијске средине, она се може израчунати тако што се израчуна збир реципрочних вредности свих брзина, а затим се \(n\) подели тим бројем. Збир реципрочних вредности се рачуна тако што се на променљиву коју иницијализујемо на нулу у петљи додају једна по једна реципрочна вредност.

Предложено решење задатка

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main(void)
{
    int i = 0;
    double x, z = 0.0, zr = 0.0;
    while (scanf("%lf", &x) != EOF)
    {
        i++;
        z += x;
        zr += 1.0 / x;
    }
    double as = z / i;
    double hs = i / zr;
    printf("%.2lf\n%.2lf", as, hs);
    return 0;
}

Просечан раст цена

Прочитај текст задатка.

Претпоставимо да је основна цена производа \(C\). Тада је цена након првог месеца једнака \(C\cdot(1+\frac{p_1}{100})\), након два месеца једнака \(C\cdot(1+\frac{p_1}{100})\cdot(1+\frac{p_2}{100})\) и тако даље, да би на крају \(n\) месеци била једнака \(C\cdot(1+\frac{p_1}{100})(1+\frac{p_2}{100})\cdot\ldots\cdot(1+\frac{p_n}{100})\). Ако би пораст цене у сваком месецу било \(p\) тада би цена након \(n\) месеци била једнака \(C\cdot(1+\frac{p}{100})^n\). Пошто желимо да овако израчунате коначне цене буду једнаке, тј. да важи \(C\cdot(1+\frac{p_1}{100})\cdot\ldots\cdot(1+\frac{p_n}{100})=C\cdot(1+\frac{p}{100})^n\), \(p\) се може израчунати као \(p=100\cdot(\sqrt[n]{(1+\frac{p_1}{100})\cdot\ldots\cdot(1+\frac{p_n}{100})}-1)\).

\(n\)-ти корен из производа \(n\) бројева назива се геометријска средина.

Производ серије можемо израчунати алгоритмом у коме резултат иницијализујемо на 1 и множимо га редом једним по једним кофицијентом повећања \(1+\frac{p}{100}\).

Корен можемо израчунати свођењем на степеновање \(\sqrt[n]{x}=x^\frac{1}{n}\) и применом функције pow

Предложено решење задатка

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <math.h>

int main(void)
{
    int n;
    double x, p = 1.0;
    scanf("%d", &n);
    for (int i = 0; i < n; i++)
    {
        scanf("%lf", &x);
        p *= (1.0 + x / 100.0);
    }
    double pp = 100.0 * (pow(p, 1.0 / n) - 1.0);
    printf("%.2lf", pp);
    return 0;
}

Производња малина

Прочитај текст задатка.

Производња сваког месеца чини геометриски низ тј. геометријску прогресију (низ бројева у коме је количник сваког члана и њему претходног константан) и у овом задатку потребно је одредити његов \(n\)-ти члан.

Маринко прве године планира да произведе \(t\) тона малина. Друге године планира за \(p\%\) више тона него прве године. Значи друге године планира да произведе \(t\cdot(1+\frac{p}{100})\) тона. Слично, треће године за \(p\%\) више тона него друге године, односно \(t\cdot(1+\frac{p}{100})\cdot(1+\frac{p}{100})\) што износи \(t\cdot(1+\frac{p}{100})^2\) тона. Закључујемо да за последњу годину, \(n\)-тy годину, планира производњу \(t\cdot(1+\frac{p}{100})^{n-1}\) тона.

У језику C степен броја се може израчунати функцијом pow декларисаном у заглављу math.h.

Предложено решење задатка (1)

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <math.h>

int main(void)
{
    int n;
    double t, p;
    scanf("%d%lf%lf", &n, &t, &p);
    double x = t * pow(1 + p / 100, n - 1); 
    printf("%.2lf", x);
    return 0;
}

Задатак може бити решен и уз помоћ петље у којој се производ иницијализује на вредност \(t\) и у сваком од \(n\) корака се множи са \(1+\frac{p}{100}\) (израчунава се производ серије), али тиме би се добило ружније и неефикасније решење.

Предложено решење задатка (2)

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main(void)
{
    int n;
    double t, p;
    scanf("%d%lf%lf", &n, &t, &p);
    double x = t;
    for (int i = 1; i < n; i++)
        x = x * (1 + p / 100);
    printf("%.2lf", x);
    return 0;
}

Сума низа бројева

Прочитај текст задатка.

Обележимо са \(a_1,a_2,\ldots,a_n\) бројеве које треба да саберемо. Oни представљају геометријски низ (у коме је количник свака два суседна броја исти) и тражена вредност је сума првих \(n\) чланова тог низа.

Једноставном анализом можемо закључити да је \(a_i=a\cdot q^{i-1}\) за \(1\leq i\leq n\). Задатак је одредити суму \(a_1+a_2+\ldots+a_{n-1}+a_n\). Обележимо тражену суму са \(S\). Применом формуле за \(a_i\) добијамо да је

\[S=a+a\cdot q^1+a\cdot q^2+\ldots+a\cdot q^{n-2}+a\cdot q^{n-1}\]

Ако леву и десну страну претходне једнакости помножимо са \(1-q\) (напоменимо \(1-q\neq 0\)) добијамо једнакост:

\[S\cdot(1-q)=a\cdot(1-q)+a\cdot q\cdot(1-q)+a\cdot q^2\cdot(1-q)+\ldots+a\cdot q^{n-2}\cdot(1-q)+a\cdot q^{n-1}\cdot(1-q)\]

Извршимо множења на десној страни једнакости:

\[S\cdot(1-q)=a-a\cdot q+a\cdot q-a\cdot q^2+a\cdot q^2-a\cdot q^3+\ldots+a\cdot q^{n-2}-a\cdot q^{n-1}+a\cdot q^{n-1}-a\cdot q^n\]

Сређивањем последњег израза добијамо \(S\cdot(1-q)=a-a\cdot q^n\). Према томе

\[S=a\cdot\frac{1-q^n}{1-q}\]

У језику C степен броја се може израчунати функцијом pow декларисаном у заглављу math.h.

Предложено решење задатка (1)

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <math.h>

int main(void)
{
    int n;
    double a, q;
    scanf("%d%lf%lf", &n, &a, &q);
    double s = a * (1 - pow(q, n)) / (1 - q);
    printf("%.5lf", s);
    return 0;
}

Рецимо и да је збир било могуће одредити и тако што бисмо употребили алгоритам сабирања елемената серије коришћењем петље, при чему бисмо сваки наредни елемент могли инкрементално израчунати од претходног множењем са \(q\).

Предложено решење задатка (2)

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main(void)
{
    int n;
    double a, q;
    scanf("%d%lf%lf", &n, &a, &q);
    double x = a;
    double s = a;
    for (int i = 1; i < n; i++)
    {
        x *= q;
        s += x;
    }
    printf("%.5lf", s);
    return 0;
}

Једнакост растојања

Прочитај текст задатка.

Тражена тачка је аритметичка средина унетих тачака.

Докажимо претходно тврђење. Ако са \(x\) означимо тражену тачку тада, за низ тачака \(x_i\), \(i=1,\ldots,n\), важи:

\[\sum_{i=1\atop x_i\leq x}^n (x-x_i)=\sum_{i=1\atop x_i>x}^n (x_i-x)\]

Ако се израз са десне стране пребаци на леву и када знак \(-\) уђе у другу суму добија се:

\[\sum_{i=1\atop x_i\leq x}^n (x-x_i)+\sum_{i=1\atop x_i>x}^n (x-x_i)=0\]

што је еквивалентно са

\[\sum_{i=1}^n (x-x_i)=0\]

Одавде се добија:

\[\sum_{i=1}^n x=n\cdot x=\sum_{i=1}^n x_i\]

Према томе, тражена тачка је аритметичка средина унетих тачака:

\[x=\frac{\sum_{i=1}^n x_i}{n}\]

Израчунавање аритметичке средине серије бројева већ смо разматрали раније. Потребно је израчунати збир елемената серије и затим га поделити са бројем елемената серије (који је у овом случају унапред познат).

Предложено решење задатка

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main(void)
{
    int n;
    scanf("%d", &n);
    double s = 0, x;
    for (int i = 0; i < n; i++)
    {
        scanf("%lf", &x);
        s += x;
    }
    printf("%.5lf", s / n);
    return 0;
}

Тежиште

Прочитај текст задатка.

Већ смо разматрали тежиште скупа тачака на правој које је одређено као просечна вредност координата тачака. Исто ће се догодити и код тачака у равни. Заиста, обележимо тежиште са \(T\), а тачке са \(A_1,\ldots,A_n\), a са \(\overrightarrow{OT}=(T_x,T_y)\), \(\overrightarrow{OA_1}=(A_{1x},A_{1y})\), …, \(\overrightarrow{OA_n}=(A_{nx},A_{ny})\) векторе њихових координата. Кренимо од услова да је \(\overrightarrow{A_1T}+\ldots+\overrightarrow{A_nT}=\overrightarrow{0}\). У последњој једнакости додамо на обе стране \(\overrightarrow{OA_1}+\overrightarrow{OA_2}+\ldots+\overrightarrow{OA_n}\) и добијамо \(n\cdot\overrightarrow{OT}=\overrightarrow{OA_1}+\overrightarrow{OA_2}+\ldots+\overrightarrow{OA_n}\), односно \(\overrightarrow{OT}=\frac{\overrightarrow{OA_1}+\overrightarrow{OA_2}+\ldots+\overrightarrow{OA_n}}{n}\).

Одатле следи:

\[T_x=\frac{A_{1x}+A_{2x}+\ldots +A_{nx}}{n}\]
\[T_y=\frac{A_{1y}+A_{2y}+\ldots +A_{ny}}{n}\]

Задатак се решава једноставним израчунавањем аритметичких средина координата \(x\) и координата \(y\) датих тачака.

Предложено решење задатка

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main(void)
{
    int n;
    scanf("%d", &n);
    double zx = 0.0, zy = 0.0, x, y;
    for (int i = 0; i < n; i++)
    {
        scanf("%lf%lf", &x, &y);
        zx += x;
        zy += y;
    }
    double tx = zx / n;
    double ty = zy / n;
    printf("%.5lf\n%.5lf", tx, ty);
    return 0;
}