Задаци: Елементарне статистике¶
Алгоритми и програми у програмском језику 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\) добијамо да је
Ако леву и десну страну претходне једнакости помножимо са \(1-q\) (напоменимо \(1-q\neq 0\)) добијамо једнакост:
Извршимо множења на десној страни једнакости:
Сређивањем последњег израза добијамо \(S\cdot(1-q)=a-a\cdot q^n\). Према томе
У језику 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\), важи:
Ако се израз са десне стране пребаци на леву и када знак \(-\) уђе у другу суму добија се:
што је еквивалентно са
Одавде се добија:
Према томе, тражена тачка је аритметичка средина унетих тачака:
Израчунавање аритметичке средине серије бројева већ смо разматрали раније. Потребно је израчунати збир елемената серије и затим га поделити са бројем елемената серије (који је у овом случају унапред познат).
Предложено решење задатка
#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}\).
Одатле следи:
Задатак се решава једноставним израчунавањем аритметичких средина координата \(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;
}