Professional Documents
Culture Documents
პროგრამირების საფუძვლები
თეორია და ამოცანები
1
არითმეტიკული და შეტანა-გამოტანის ოპერაციები
+ შეკრება
– გამოკლება
* გამრავლება
/ გაყოფა (როგორც მთელი, ასევე მოძრავმძიმიანი)
% ნაშთის გამოთვლა
++ ინკრემენტი (1–ით გაზრდა)
–– დეკრემენტი (1–ით შემცირება)
3
მიაქციეთ ყურადღება გამოსახულების ბოლოში დასმულ წერტილ-მძიმეს. C++-ში
აუცილებელია ნებისმიერი ბრძანება წერტილ-მძიმეთი მთავრდებოდეს.
ჯამი შეიძლება გამოვთვალოთ უშუალოდ გამოტანის ოპერატორში ან შეგვიძლია
გამოტანამდე სხვა ცვლადს მივანიჭოთ მისი მნიშვნელობა.
ახლა ვნახოთ როგორ გამოიყურება პროგრამა სრული სახით.
#include<iostream> #include<stdio.h>
using namespace std; int N,k;
int N; main(){
main(){ scanf("%d",&N);
cin>>N; k=N/10+N%10;
cout<<N/10+N%10; printf("%d”,k);
} }
ორივე კოდი ჩვენს ამოცანაზე ერთსა და იმავე პასუხებს იძლევა. განსხვავება მხოლოდ ის
არის, რომ პირველი მათგანი C++-ის ბრძანებებითაა დაწერილი, ხოლო მეორე მხოლოდ C-ის
საშუალებებსაც იყენებს. პირველ პროგრამაში 3 ბრძანებაა, ხოლო მეორეში – 2 (ისინი მუქი
ფონითაა გამოყოფილი). დანარჩენი სტრიქონები შეიძლება შაბლონად ჩავთვალოთ და ყველა
პროგრამისთვისაა აუცილებელი. ორივე პროგრამის პირველ სტრიქონში მოცემულია ე.წ.
დირექტივა, რომელიც განსაზღვრავს, თუ რომელი სტანდარტული ფაილები უნდა ჩაერთოს
ჩვენ მიერ დაწერილი პროგრამის შესრულებაში. include-ში მითითებულია კონკრეტული
ფაილების (ზოგჯერ მათ ბიბლიოთეკებსაც უწოდებენ) სახელები, რომლებიც უზრუნველყოფენ
C-ის და C++-ის ამა თუ იმ ფუნქციის შესრულებას.
სტრიქონები int N,k; და int N; წარმოადგენენ ცვლადთა აღწერის ინსტრუქციას.
პირველ შემთხვევაში აღწერილია მთელი ტიპის (ამას განსაზღვრავს სიტყვა int ) ორი ცვლადი,
ხოლო მეორე შემთხვევაში – ერთი. ცვლადის აღწერა კომპილატორს სჭირდება მისთვის
საკმარისი მეხსიერების გამოსაყოფად.
main() წარმოადგენს პროგრამის მთავარი ფუნქციის სახელს (პროგრამისტს შეუძლია
თავადაც შექმნას ფუნქციები და დაარქვას მათ სახელები) და ყველა ბრძანება მოთავსებული
უნდა იყოს მისთვის განკუთვნილ ფიგურულ ფრჩხილებს შორის.
cin და cout ოპერატორების, ისევე როგორც C++-ის სხვა ოპერატორების, გამოყენებისას
აუცილებელია პროგრამის დასაწყისში „using namespace std“–ს მითითება. პირდაპირ
თარგმანში ეს ფრაზა ნიშნავს „გამოიყენე std–ს სახელთა სივრცე“. std–ს სახელთა სივრცეს კი
გამოიყენებს პრაქტიკულად ყველა ბიბლიოთეკა, რომელიც C++-ში ფუნქციონირებს.
მიაქციეთ ყურადღება, რომ scanf–ის გამოყენებისას ცვლადის სახელის წინ
აუცილებელია სიმბოლო „&“–ის გამოყენება, რაც აღნიშნავს შესაბამისი ცვლადის მისამართს
მეხსიერებაში. printf–ის მუშაობისას გამოიყენება ე.წ. გამოტანის შაბლონი, რომელიც
ბრჭყალებს შორის არის მოთავსებული, და გამოტანის სპეციფიკაცია (%d), რომელიც
მიუთითებს გამოსატანი ცვლადის ფორმატს (ჩვენს ამოცანაში „%d“ მთელი რიცხვის ფორმატს
აღნიშნავს). შედეგების გამოტანისას „%d“–ის ნაცვლად დაიბეჭდება k ცვლადის მნიშვნელობა.
4
ანალიზი. ამ ამოცანაში გამოსატანი მონაცემები მთელი ტიპის არ არის, ამიტომ უნდა
გამოვიყენოთ რომელიმე მოძრავძიმიანი ტიპი float ან double, თუმცა სწორი პასუხის
მისაღებად მხოლოდ აღწერა საკმარისი არ არის. რადგან (a+b)/2 გამოსახულებაში ორივე
ცვლადი მთელი ტიპისაა, შესრულდება მთელი გაყოფის ოპერაცია და რიგ შემთხვევაში
პროგრამა არასწორ პასუხს გამოიტანს. მაგ. ამოცანის მეორე ტესტში 22.5-ის ნაცვლად მივიღებთ
22.0-ს. ასეთი უზუსტობის თავიდან ასაცილებლად საჭიროა გამოსათვლელი გამოსახულების
წინ მივუთითოთ ჩვენთვის სასურველი ტიპი.
ორი მთელი რიცხვის საშუალო არითმეტიკული მძიმის შემდეგ მხოლოდ ერთ რიცხვს
შეიძლება შეიცავდეს. გარკვეული მოქმედებებია საჭირო იმისათვის, თუ გვინდა, რომ
ათწილადში ზედმეტი 0-ები არ დაიბეჭდოს. მძიმის შემდეგ ციფრის რაოდენობა cout-სათვის
რეგულირდება setprecision ბრძანებით (სჭირდება ბიბლიოთეკა <iomanip.h>). იგივე
საკითხი printf-ის გამოყენებისას გამოსატანი რიცხვის სპეციფიკაციაში მიეთითება (“%.1f).
#include<stdio.h> #include<iostream>
int a,b; #include <iomanip.h>
float c; using namespace std;
int a,b;
main(){ double x;
scanf("%d%d",&a,&b); main(){
c=(float) (a+b)/2; cin>>a>>b;
printf("%.1f",c); x=(double) (a+b)/2;
} cout<< setprecision(1)<<x<<endl;
}
#include <iostream>
using namespace std;
int a,b;
main(){
cin>>a>>b;
cout<<a*30.48+b*2.54;
}
5
შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი
845 548
601 106
#include<stdio.h> #include<iostream>
int n,a,b,c; using namespace std;
int n,a,b,c;
main(){ main(){
scanf("%d",&n); cin>>n;
a=n%10; b=(n/10)%10; c=n/100; a=n%10; b=(n%100)/10; c=n/100;
printf("%d%d%d",a,b,c); n=a*100+b*10+c;
} cout<<n<<endl;
}
6
ამოცანა 6. დროის შუალედი
მეტეოროლოგმა ჩაიწერა მზის ამოსვლის და ჩასვლის დროები წამების სიზუსტით.
თითოეული ჩანაწერი მოცემულია ჰარით გაყოფილი სამი მთელი A , B და C რიცხვებით,
რომლებიც შესაბამისად აღნიშნავენ საათს, წუთსა და წამს (1 ≤ A ≤ 23; 0 ≤ B, C ≤ 59). დაწერეთ
პროგრამა, რომელიც გამოითვლის რამდენი წამი გავიდა დროის ამ ორ მომენტს შორის.
შესატანი მონაცემები: ორი სტრიქონიდან თითოეულში მოცემულია სამ-სამი მთელი
რიცხვი – შესაბამისად მზის ამოსვლის და ჩასვლის დროები.
გამოსატანი მონაცემები: ერთი მთელი რიცხვი – განსხვავება დროის ორ მომენტს შორის
წამებში.
#include<iostream>
using namespace std;
int a1,b1,c1,a2,b2,c2,x,y;
main(){
cin>>a1>>b1>>c1;
cin>>a2>>b2>>c2;
x=a1*3600+b1*60+c1;
y=a2*3600+b2*60+c2;
cout<<y-x;
}
7
ანალიზი. რადგან ქვების შეტრიალება ნებადართულია და თითოეული ქვა ზუსტად ორ
უჯრას ფარავს, ცხადია, რომ ნებისმიერი ლუწი სიგრძის სტრიქონის ან სვეტის დაფარვა
სრულადაა შესაძლებელი. ამ ფაქტის გამო დაფა მთლიანად დაიფარება ქვებით, თუკი მისი
ერთ–ერთი გვერდი მაინც არის ლუწი სიგრძის. თუ ორივე გვერდი კენტი სიგრძისაა, მაშინ
შეუვსებელი დარჩება მხოლოდ ერთი უჯრა.
#include<iostream>
using namespace std;
int m,n;
main(){
cin>>m>>n;
cout<<m*n/2;
}
#include<iostream>
using namespace std;
int m,n,a;
main(){
cin>>m>>n>>a;
cout<<((m+a–1)/a)*((n+a–1)/a);
}
ამოცანა 9. ქათამნახევარი
ფერმის ხელმძღვანელობამ გამოთვალა, რომ საშუალოდ ქათამნახევარი დღენახევარში
კვერცხნახევარს დებს. გამოთვალეთ რამდენ კვერცხს დებს n ქათამი m დღეში?
შესატანი მონაცემები: მოცემულია ორი მთელი რიცხვი – n და m (1<n,m≤1000). n და m
ექვსის ჯერადები არიან.
გამოსატანი მონაცემები: ერთი მთელი რიცხვი – ქათმების მიერ დადებული კვერცხების
რაოდენობა.
8
შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი
69 36
#include <iostream>
using namespace std;
int n,m;
main(){
cin>>n>>m;
cout<<n*m/1.5;
}
#include<stdio.h> #include<iostream>
#include<stdlib.h> #include<stdlib.h>
int n,a,b; #include <iomanip.h>
float c; using namespace std;
int a,b;
main(){ double x;
scanf("%d%d",&a,&b); main(){
c=(float) a/b -(int) a/b; cin>>a>>b;
printf("%.3f",c); x=(double) a/b-(int) a/b;
} cout<<setprecision(3)<<x;
}
9
ამოცანა 11. საახალწლო სანთლები
(http://codeforces.com/problemset/problem/379/A)
ვასოს რომანტიკა უყვარს, ამიტომ გადაწყვიტა საახალწლოდ ოთახი სანთლებით
გაანათოს. მას აქვს a ცალი სანთელი. როცა ვასო ანთებს ახალ სანთელს, ის იწვის ზუსტად 1
საათი და შემდეგ ქრება. b ცალი ჩამქრალი სანთლიდან ვასო აკეთებს ერთ სანთელს, რომელიც
შეუძლია ახალივით გამოიყენოს.
ახლა ვასოს აინტერესებს, რამდენ საათის განმავლობაში ეყოფა მას თავისი სანთლები,
თუკი ოპტიმალურად იმოქმედებს. დაწერეთ პროგრამა, რომელიც გამოთვლის ამ რიცხვს.
შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია ორი მთელი რიცხვი
a და b (1≤a≤1000; 2≤b≤1000).
გამოსატანი მონაცემები: ერთი მთელი რიცხვი – საათების რაოდენობა, რომლის
განმავლობაშიც ვასოს შეუძლია ოთახის განათება.
ანალიზი. პასუხი მოთავსებული იქნება a–სა და 2*a–ს შორის, რადგან ყველაზე უკეთეს
შემთხვევაშიც კი, როცა 2 ჩამქრალი სანთლიდან ერთი ახალი კეთდება, ახალი სანთლების
რაოდენობა a–ს არ აღემატება. თუ გავითვალისწინებთ, რომ ყოველი ახალი სანთლის
გაკეთებისას ჩამქრალი სანთლების რაოდენობა (b–1)–ით მცირდება, ხოლო საბოლოოდ 1 მაინც
გამოუყენებელი ჩამქრალი სანთელი დაგვრჩება, ამოცანის პასუხი შეიძლება გამოვთვალოთ
ფორმულით: a+(a–1)/(b–1)=(a*b-1)/(b-1).
#include<iostream>
using namespace std;
int main(){
int a,b;
cin>>a>>b;
cout<<(a*b-1)/(b-1)<<endl;
}
10
ანალიზი. ვთქვათ, პარალელეპიპედის წიბოებია a, b და c, მაშინ მეორე ტესტში
შემომავალი სამი რიცხვისთვის გვექნება a*b=4; a*c=6 და b*c=6; თუ აქ მარჯვენა და მარცხენა
მხარეებს შესაბამისად გადავამრავლებთ და ორივე მხრიდან ფესვს ამოვიღებთ, გვექნება
a*b*c=12. აქედან უკვე შეგვიძლია გვერდის სიგრძეების გაგება: c=(a*b*c)/(a*b)=12/3=4.
b=(a*b*c)/(a*c)=12/6=2 და b=(a*b*c)/(a*b)=12/6=2. პასუხის მისაღებად წიბოთა ჯამი 4-ზე უნდა
გავამრავლოთ.
#include <iostream>
using namespace std;
int a,b,c,s;
main(){
cin>>a>>b>>c;
s=sqrt(a*a+b*b+c*c);
cout<<4*(s/a+s/b+s/c);
}
ამოცანა 13. R2
ხორვატიის ღია პირველობა ინფორმატიკაში (2006/07 წელი, შეჯიბრი 2)
S რიცხვს უწოდებენ R1 და R2 რიცხვების საშუალოს, თუ S უდრის (R1+R2)/2–ს. სლავკოს
მირკომ დაბადების დღეზე ორი მთელი რიცხვი აჩუქა: R1 და R2. სლავკომ სწრაფად გამოთვალა
მათი საშუალო, რომელიც ასევე მთელი რიცხვი აღმოჩნდა, მაგრამ მოულოდნელად დაკარგა R2!
დაეხმარეთ სლავკოს R2–ის აღდგენაში.
შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია ორი მთელი რიცხვი R1 და S.
თითოეული მათგანის მნიშვნელობა მოთავსებულია დიაპაზონში -1000–დან 1000–მდე.
გამოსატანი მონაცემები: ერთი მთელი რიცხვი – R2.
11
შედარების ოპერატორი
შედარების ოპერატორი გამოიყენება პროგრამაში განშტოებათა ორგანიზებისათვის (ამის
გამო მას ხშირად განშტოების ოპერატორს უწოდებენ). მისი ფორმატია:
if (გამოსახულება) ოპერატორი1; [else ოპერატორი2;]
if ოპერატორის შესრულება იწყება გამოსახულების მნიშვნელობის გამოთვლიდან,
რომელსაც ორი შესაძლო პასუხი აქვს – ჭეშმარიტი (ანუ განსხვავებულია 0–საგან) და მცდარი
(ანუ 0). შემდეგ შესრულება გრძელდება ამგვარი სქემით:
▪ თუ გამოსახულება ჭეშმარიტია, სრულდება ოპერატორი1.
▪ თუ გამოსახულება მცდარია, სრულდება ოპერატორი2.
▪ თუ გამოსახულება მცდარია და ოპერატორი2 არაა მოცემული, მაშინ სრულდება
ოპერატორი , რომელიც უშუალოდ if–ის შემდეგაა.
▪ ერთდროულად ოპერატორი1–ის და ოპერატორი2–ის შესრულება შეუძლებელია.
დასაშვებია ერთმანეთში ჩადგმული if ოპერატორების გამოყენება. იგი შესაძლოა
ჩადგმული იქნას სხვა if–ის (ან სხვა else–ს) შიგნით. ასეთ დროს რეკომენდირებულია
ფიგურული ფრჩხილების გამოყენება, რომელთა არარსებობის შემთხვევაში კომპილიატორი
თავად აწყვილებს else–ებს უახლოეს if–ებთან, რომელსაც else არ აქვს.
ოპერატორი შედეგი
== ტოლია
!= არ უდრის
> მეტია
< ნაკლებია
>= მეტია ან ტოლი
<= ნაკლებია ან ტოლი
12
switch (გამოსახულება) {
case ჭდე1:
ოპერატორთა მიმდევრობა;
break;
case ჭდე2:
ოპერატორთა მიმდევრობა;
break;
case ჭდე3:
ოპერატორთა მიმდევრობა;
break;
default:
ოპერატორთა მიმდევრობა;
}
გამოსახულების მნიშვნელობა ოპერატორ switch–ში შეიძლება გამოისახოს მხოლოდ
მთელი რიცხვით. სიმბოლური ჭდეების გამოყენების შემთხვევაში მხედველობაში მიიღება
მათი რიცხვითი მნიშვნელობები. გამოსახულების მნიშვნელობა რიგრიგობით ედარება ჭდეებს
და თუ რომელიმეს ტოლია, სრულდება ოპერატორების ჯგუფი შესაბამისი case–დან
ოპერატორ break–მდე. თუკი case–ს break–ი არ ახლავს, პროგრამა ასრულებს მომდევნო
case–ების ოპერატორებს ვიდრე არ შეხვდება break–ი ან არ დამთავრდება switch
ოპერატორის ტანი. ოპერატორი default სრულდება მაშინ, თუ გამოსახულების მნიშვნელობა
არ დაემთხვა არცერთ ჭდეს. default–ის გამოყენება switch–ში აუცილებელი არ არის და
თუკი მისი არარსებობის შემთხვევაში გამოსახულების მნიშვნელობა არ დაემთხვა არცერთ
ჭდეს, მაშინ არანაირი ოპერატორი არ სრულდება.
С++–ის სტანდარტის მიხედვით switch–ში შესაძლებელია 1023 ჭდის გამოყენება, რაც
პრაქტიკულად შეუძლებელია, რომ პროგრამის წერის დროს დაგვჭირდეს. ორ ან მეტ ჭდეს არ
შეიძლება ერთნაირი მნიშვნელობა ჰქონდეს. შესაძლებელია ერთ switch–ში მეორის ჩადგმა.
13
#include <iostream>
using namespace std;
long long v, n, b ;
main(){
cin >> v >> n;
b = v/3;
if (b < n) cout << "YES " << n-b << endl;
else cout << "NO";
}
#include <iostream>
using namespace std;
long long m,n,k,t,v,s;
main(){
cin>>n>>m>>k;
t=60*n+m;
v=16*t;
s=k*1024;
if (v<=s) cout<<"YES\n";
else cout<<"NO\n"<<v-s<<endl;
}
14
ამოცანა 16. გამრავლება
ბულგარეთის ეროვნული ოლიმპიადა (2010 წელი, საწყისი ეტაპი, 4-5 კლასი)
მოცემულია სამნიშნა რიცხვი. დაწერეთ პროგრამა, რომელიც დაადგენს იმ უდიდესი
რიცხვის მნიშვნელობას, რომელიც შესაძლოა მივიღოთ ამ რიცხვის ციფრებს შორის
გამრავლების ერთი ნიშნის ჩასმით.
შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია ერთი მთელი სამნიშნა რიცხვი.
გამოსატანი მონაცემები: ერთადერთ სტრიქონში გამოიტანეთ მაქსიმალური შესაძლო
პასუხი.
15
}
ამოცანა 18. სამკუთხედის აგება
დაწერეთ პროგრამა, რომელიც მოცემული სამი A, B და C (0 <= A, B, C <= 30000)
რიცხვებისათვის შეამოწმებს, შესაძლებელია თუ არა შესაბამისი სიგრძეების მონაკვეთებით
სამკუთხედის აგება. დადებითი პასუხის შემთხვევაში პროგრამამ გამოიტანოს – “YES”, თუკი
სამკუთხედი არ აიგება – “NO”.
შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია სამი მთელი A, B და C.
გამოსატანი მონაცემები: გამოიტანეთ YES, თუ სამკუთხედის აგება შესაძლებელია და
წინააღმდეგ შემთხვევაში გამოიტანეთ NO.
16
ამოცანა 11. პეტრე და ჯავა
http://codeforces.com/problemset/problem/66/A
პატარა პეტრემ პროგრამირების შესწავლა დაიწყო და დიდი ფიქრის შემდეგ გადაწყვიტა,
რომ არჩევანი ჯავაზე შეეჩერებინა. მთავარ არგუმენტად ამ არჩევანის დროს იყო ის ფაქტი, რომ
ჯავაში არის ძალიან დიდი მთელი ტიპი - BigInteger. თუმცა პროგრამირების წრეში პეტრემ
გაიგო, რომ BigInteger-ის გამოყენება ყველა ამოცანაში არ არის საჭირო და ხშირად
მოსახერხებელია უფრო ნაკლები დიაპაზონის მქონე ცვლადთა ტიპების გამოყენება. ამის გამო
წარმოიშვა კითხვა: „რომელი მთელი ტიპი გამოვიყენოთ ნატურალური n რიცხვის შესანახად?“
პეტრემ იცის მხოლოდ 5 მთელი ტიპი:
1) byte – 1-ბაიტიანი მონაცემი დიაპაზონით -128..127.
2) short – 2-ბაიტიანი მონაცემი დიაპაზონით -32768..32767.
3) int – 4-ბაიტიანი მონაცემი დიაპაზონით -2147483648..2147483647.
4) long– 8-ბაიტიანი მონაცემი დიაპაზონით -9223372036854775808..9223372036854775807.
5) BigInteger ინახავს ნებისმიერ მთელ რიცხვს, მაგრამ იმის გამო, რომ არ წარმოადგენს
პრიმიტიულ ტიპს, გაცილებით ნელა მუშაობს.
დიაპაზონთა საზღვრები ეკუთვნიან ამავე დიაპაზონს. პეტრეს სურს, რომ მოცემული n
რიცხვი შეინახოს რაც შეიძლება ნაკლები დიაპაზონის ტიპში.
შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია ერთი მთელი დადებითი
რიცხვი - n. ის შედგება არაუმეტეს 100 ციფრისაგან და არ იწყება 0–ებისაგან. n არ შეიძლება
იყოს ცარიელი სტრიქონი.
გამოსატანი მონაცემები: გამოიტანეთ პირველივე ტიპი სიიდან "byte, short, int, long,
BigInteger", რომელშიც შეიძლება შენახული იყოს n რიცხვი, ზემოთ მითითებული
დიაპაზონების მიხედვით.
#include <iostream>
using namespace std;
int main() {
long double nb;
cin>>nb;
if(nb<=127) cout<<"byte";
else if(nb<=32767) cout<<"short";
else if(nb<=2147483647) cout<<"int";
else if(nb<=9223372036854775807LL) cout<<"long";
else cout<<"BigInteger";
}
17
ამოცანა 21. მეოთხე წერტილი
ხორვატიის ღია პირველობა ინფორმატიკაში (2007/08 წელი, შეჯიბრი 1)
მირკოს უნდა შეარჩიოს 4 წერტილი სიბრტყეზე ისე, რომ ისინი ჰქმნიდნენ მართკუთხედს,
რომლის გვერდები საკოორდინატო ღერძების პარალელურია. მან უკვე შეარჩია 3 წერტილი და
დარწმუნებულია, რომ შეცდომა არ დაუშვია. მეოთხე წერტილის შერჩევა კი გაუჭირდა.
დაეხმარეთ მირკოს და დაწერეთ პროგრამა, რომელიც იპოვის მეოთხე წერტილის
კოორდინატებს.
შესატანი მონაცემები: სამი სტრიქონიდან თითოეულში მოცემულია ორ-ორი მთელი
რიცხვი – შესაბამის წერტილის კოორდინატები სიბრტყეზე. თითოეული კოორდინატი
წარმოადგენს მთელ რიცხვს და მოთავსებულია დიაპაზონში 1-დან 1000-მდე.
გამოსატანი მონაცემები: ერთადერთ სტრიქონში გამოიტანეთ ორი მთელი რიცხვი –
მეოთხე წერტილის კოორდინატები.
#include <iostream>
int x1, y1, x2, y2, x3, y3;
main( ) {
cin>>x1>>y1>>x2>>y2>>x3>>y3;
if( x1 == x2 ) cout<<x3<<” “;
if( x1 == x3 ) cout<<x2<<” “;
if( x2 == x3 ) cout<<x1<<” “;
if( y1 == y2 ) cout<<y3<<endl;
if( y1 == y3 ) cout<<y2<<endl;
if( y2 == y3 ) cout<<y1<<endl;
}
19
ამოცანა 24. პოსტების რეიტინგი
Geolymp (2011 წელი, პირველი ეპიზოდი, ელდარ ბოგდანოვი)
ხშირად ფორუმებზე შეიძლება მომხმარებლის პოსტის სასარგებლოდ და
საწინააღმდეგოდ ხმის მიცემა. პოსტის საწყისი რეიტინგი 0-ის ტოლია. ცხადია, რომ რაც უფრო
მაღალი რეიტინგი აქვს პოსტს, იგი მით უფრო საინტერესო და სასარგებლოდ ითვლება.
ყველაზე საზიზღარი პოსტები კი უარყოფითი რეიტინგით გამოირჩევა.
ჩვენ ვიმყოფებით ისეთ ფორუმზე, სადაც დადებითი ხმა პოსტის რეიტინგს 2-ით ზრდის,
ხოლო უარყოფითი 1-ით ამცირებს. გვაქვს რაღაც პოსტი, რომლის მიმდინარე რეიტინგი არის R.
დაადგინეთ, მინიმუმ რამდენ ადამიანს უნდა მიეცა ხმა ამ პოსტისთვის ასეთი რეიტინგის
მისანიჭებლად. ერთ ადამიანს კონკრეტული პოსტისთვის ხმის მიცემა მხოლოდ ერთხელ
შეუძლია.
შესატანი მონაცემები: ერთადერთი სტრიქონი შეიცავს ერთ მთელ რიცხვს R (-100 ≤ R≤100).
გამოსატანი მონაცემები: დაბეჭდეთ მომხმარებლების ის მინიმალური რაოდენობა,
რომელიც საკმარისია პოსტისთვის R რეიტინგის მისანიჭებლად.
#include <iostream>
int R;
main(){
cin>>R;
if (R<0) cout<<-R; else cout<<(R+1)/2;
}
ამოცანა 25. მატჩი
Geolymp (2011 წელი, მეოთხე ეპიზოდი, გიორგი საღინაძე)
ერთი პატარა ქვეყნის ფეხბურთის ეროვნულ ჩემპიონატში მონაწილე ერთ-ერთი გუნდის
რამოდენიმე წევრმა კორუფციული გარიგება დადო ტოტალიზატორის შავი ბიზნესის
წარმომადგენლებთან, რის შედეგადაც მათ საკმაოდ დიდ თანხა უნდა მიეღოთ. გარიგების
თანახმად ფეხბურთის გუნდს უნდა აეკიდებინა მინიმუმ A ცალი პენალტი, B ცალი აუტი და C
ცალი ყვითელი ბარათი. თუ ამ სამი პირობიდან 2-ს მაინც არ შეასრულებდნენ, მაშინ
სერიოზული პრობლემები შეექმნებოდათ. მანაოს ყურამდე რა თქმა უნდა მიაღწია ამ გარიგებამ,
მან ყურადღებით უყურა თამაშს და დაიმახსოვრა პენალტების, აუტების და ყვითელი
ბარათების რაოდენობა - AM, BM, CM.
მოცემულია გარიგების დეტალები და მანაოს მიერ დათვლილი შედეგები. დაადგინეთ,
შეასრულა თუ არა გუნდმა შეთანხმება.
შეზღუდვები: 0 <= A, AM <= 3, 0 <= B, BM <= 20, 0 <= C, CM <= 10.
შესატანი მონაცემები: ერთადერთი სტრიქონი შეიცავს ჰარით გამოყოფილ 6 მთელ
რიცხვს: A, B, C, AM, BM, CM.
გამოსატანი მონაცემები: ერთადერთი სტრიქონში დაბეჭდეთ სიტყვა "YES", თუ გუნდმა
შეასრულა შეთანხმება და "NO" – წინააღმდეგ შემთხვევაში.
20
შესატანი მონაცემები გამოსატანი მონაცემები
1 12 4 1 13 5 YES
1 12 4 0 15 2 NO
#include <iostream>
int A, B, C, AM, BM, CM, cnt;
main(){
cin>> A>>B>>C>>AM>>BM>>CM;
cnt=0;
if (A >= AM) cnt = cnt + 1;
if (B >= BM) cnt = cnt + 1;
if (C >= CM) cnt = cnt + 1;
if (cnt >= 2) cout<<“YES“; else cout<<“NO“;
}
21
ციკლის ოპერატორები
22
უპირობო ციკლის ზოგადი კონსტრუქცია პროგრამირების ყველა ენაში თითქმის
ერთნაირია, მაგრამ C++–ში დამატებულია ზოგიერთი ისეთი შესაძლებლობა, რომელიც მას
განსაკუთრებით მოქნილს ხდის. მაგალითად, for ციკლში დასაშვებია ერთდოულად
რამდენიმე ცვლადის გამოყენება ციკლის ცვლადად. ასეთ შემთხვევაში ოპერატორების
გამყოფად მძიმე გამოიყენება:
for(x=0, y=3; x+y<14; x++, y+=2)
მკაცრი შეზღუდვები არ ადევს ციკლის შესრულების პირობასასც. აქ შეიძლება
გამოყენებულ იქნას ნებისმიერი სახის ლოგიკური გამოსახულება (რომელშიც შესაძლოა
ციკლის ცვლადი საერთოდ არ ფიგურირებდეს). ზოგადად, for ციკლის სამი სექციიდან
თითოეულში შესაძლოა განთავსდეს ნებისმიერი სახის სინტაქსურად სწორი გამოსახელება.
უფრო მეტიც, ზოგიერთი ან ყველა სექცია შეიძლება საერთოდ ცარიელი იყოს. მაგალითად,
ქვემოთ მოყვანილ კოდში ციკლი სრულდება მანამ, ვიდრე მომხმარებელი კლავიატურიდან არ
შეიყვანს რიცხვს 16:
for(x=0; x!=16; )
scanf("%d", &x);
ბიჯის სექცია აქ უბრალოდ ცარიელია და ციკლის ცვლადის ზრდა არ ხდება. ყოველი
იტერაციის წინ მოწმდება პირობა, უდრის თუ არა კლავიატურიდან შეყვანილი რიცხვი 16–ს და
რადგან შემოწმება ხდება პირობით „არ უდრის“, 16–ის აკრების შემთხვევაში პირობა გახდება
მცდარი და პროგრამა გამოვა ციკლიდან.
ციკლის ცვლადის ინიციალიზაცია შეიძლება for ციკლის დაწყებამდე მოხდეს. ეს
განსაკუთრებით მაშინაა საჭირო, როცა ციკლის ცვლადის საწყისი მნიშვნელობა სხვა ცვლადზეა
დამოკიდებული. მაგალითად,
if(k==1) x = 24; else x = 10;
for( ; x<10; ) {
printf("%d", x);
++x;
}
უსასრულო ციკლის ორგანიზებისათვის საკმარისია for ოპერატორში სამივე სექცია
ცარიელი დავტოვოთ. ცხადია, რომ ასეთი ციკლიდან გამოსასვლელად პროგრამამ გარკვეული
მოქმედებები ციკლის ტანში უნდა შეასრულოს. ქვემოთ მოყვანილ კოდში უსასრულო ციკლი
შესრულდება მანამ, ვიდრე მომხმრებელი კლავიატურაზე არ აკრებს სიმბოლო 'A'–ს.
for( ; ; ) {
ch = getchar();
if(ch=='A') break;
}
C++–ში შესაძლებელია ცვლადების გამოცხადება უშუალოდ for ციკლის
ინიციალიზაციისას. ასეთ შემთხვევაში ცვლადი წარმოადგენს მოცემული ციკლის ლოკალურ
ცვლადს და ციკლის გარეთ მისი გამოყენება შეუძლებელია. მაგალითად, კოდში
for(int i = 0; i<10; i++){
int j = i * i;
}
int k=i+ 10;
ბოლო სტრიქონი გამოიწვევს შეცდომის შეტყობინებას, რადგან ციკლის ცვლადი ციკლის
შიგნითაა აღწერილი და ციკლის გარე ნაწილი მას ვერ ხედავს.
23
ამოცანა 26. კენტი რიცხვების ჯამი
დაწერეთ პროგრამა, რომელიც გამოითვლის A-დან B-მდე ყველა კენტი რიცხვის ჯამს.
შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია ჰარით დაშორებული ორი
მთელი რიცხვი A და B (0 <= A, B <= 200) .
გამოსატანი მონაცემები: ერთადერთ სტრიქონში გამოიტანეთ ერთი მთელი რიცხვი – A-
დან B-მდე ყველა კენტი რიცხვის ჯამი.
შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი
22 29 104
განმარტება: 36-ის გამყოფებია - 1, 2, 3, 4, 6, 9, 12, 18, 36. სულ მათი რაოდენობაა 9. 25-ის
გამყოფებია - 1, 5, 25.
#include <iostream>
int a,c,i;
main(){
cin>>a;
for (i=1; i<= a; i++)
if (a%i==1)c++;
cout<<c;
}
24
ამოცანა 28. Bedtime Reading - ძილის წინ საკითხავი
USACO 2006 წლის USA OPEN, “ბრინჯაოს” დივიზიონი
ფერმერი ჯონი ასრულებს თავის მოვალეობას: ძილის წინ წიგნები წაუკითხოს ბესის.
"ოჰ, ეს მე თავს მტკენს" - წუწუნებს ბესი.
"ეს ხომ უბრალო რიცხვთა თეორიაა" - პასუხობს ჯონი - "მოდი გავიაროთ კიდევ
ერთხელ. რიცხვის სიგმა ფუნქცია არის ამ რიცხვის გამყოფების ჯამი. მაგალითად,
12-ის გამყოფებია: 1, 2, 3, 4, 6 და 12. ამ რიცხვების შეკრებით მიიღება 28.
"სულ ეს არის" - კითხულობას ბესი – "იქნებ ვინმემ დაწეროს პროგრამა,
რომელიც იპოვის სიგმა ფუნქციას რიცხვისათვის I (1 <= I <= 1,000,000)."
შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია ერთი მთელი რიცხვი I .
გამოსატანი მონაცემები: ერთადერთ სტრიქონში გამოიტანეთ I-ს ყველა გამყოფის ჯამი.
25
ანალიზი. მიმდევრობის რიცხვები წაკითხვისთანავე შევაბრუნოთ და დავბეჭდოთ.
რადგან ყველა რიცხვი ორნიშნაა, შებრუნება მარტივად ხდება 10-ზე გაყოფის ნაშთით და 10-ზე
მთელი გაყოფით.
#include <iostream>
int n,i,a;
main( ) {
cin>>n;
for (i=1; i<=n; i++){
cin>>a;
cout<<10*(a%10)+a/10;}
}
26
ამოცანა 31. Ice Cream - ნაყინი [Burch, 2001]
USACO 2001 წლის გაზაფხულის შეჯიბრი, “ნარინჯისფერი” დივიზიონი
როცა ფერმერი ჯონი კვებავს საკუთარ ძროხებს, გასართობად ერთგვარ თამაშსაც
თამაშობს. ის მიუყვება მწკრივში განლაგებულ ძროხებს და თანმიმდევრულად კითხულობს
მათ ყურებზე დაწერილ ნომრებს. ჯონი ცდილობს გამოიცნოს ლუწი ნომრებისაგან შედგენილი
ყველაზე გრძელი უწყვეტი მიმდევრობის სიგრძე და თუ ეს შეძლო, სადილის შემდეგ
უგემრიელეს ნაყინს მიიღებს.
მოცემულია ძროხათა რაოდენობა N (1 <= N <= 100,000) და N ცალი ნომერი დიაპაზონში
1..1,000,000. იპოვეთ ლუწი ნომრებით შედგენილი უგრძელესი უწყვეტი მიმდევრობის სიგრძე.
შესატანი მონაცემები: პირველ სტრიქონში მოცემულია ერთი მთელი რიცხვი N. მომდევნო
N სტრიქონიდან თითოეულში მოცემულია თითო მთელი რიცხვი - შესაბამისი ძროხის ნომერი.
გამოსატანი მონაცემები: ერთადერთ სტრიქონში გამოიტანეთ ერთი მთელი რიცხვი -
ლუწი ნომრებისაგან შედგენილი ყველაზე გრძელი უწყვეტი მიმდევრობის სიგრძე.
შესატანი მონაცემები გამოსატანი მონაცემი
7 3
1
2
4
6
3
4
12
#include <iostream>
using namespace std;
main() {
int n, w=0, h=0,old=-1, current;
cin>>n;
for( int i = 0; i < n; i++ ) {
cin>> current;
if (current==old) h++; else h=1;
if (h>w) w=h;
old=current;
}
cout<<w<<endl;
}
ამოცანა 33 – ტრამვაი
http://codeforces.com/problemset/problem/116/A
წრფივ სახელმწიფოში ტრამვაის მხოლოდ ერთი მარშრუტია. ის შედგება n გაჩერებისაგან,
რომლებიც გადანომრილია 1-დან n-მდე ტრამვაის მოძრაობის მიმართულებით. i-ურ
გაჩერებაზე ai რაოდენობის ადამიანი ჩამოდის ტრამვაიდან, ხოლო bi რაოდენობის - ამოდის.
ტრამვაი პირველ გაჩერებაზე ცარიელი მოდის, ხოლო ბოლო გაჩერებაზე ყველა მგზავრი
ჩამოდის.
თქვენი ამოცანაა დაადგინოთ ტრამვაის მინიმალური ტევადობა, რომელსაც არასდროს არ
აღემატება ტრამვაიში მყოფ მგზავრთა რაოდენობა დროის ნებისმიერი მომენტისათვის.
გაითვალისწინეთ, რომ ყოველ გაჩერებაზე მგზავრები ჯერ ჩადიან ტრამვაიდან და მხოლოდ
ამის შემდეგ ამოდიან ახალი მგზავრები.
შესატანი მონაცემები: პირველ სტრიქონში მოცემულია ერთი მთელი რიცხვი n (2≤n≤1000).
მომდევნო n სტრიქონიდან თითოეულში მოცემულია ორ-ორი მთელი რიცხვი ai და bi
(0≤ai,bi≤1000) – იმ მგზავრთა რაოდენობა, რომლებიც შესაბამის გაჩერებაზე ჩადიან და ამოდიან.
გაჩერებები ჩამოთვლილია იმ მიმდევრობით, როგორც მათ ტრამვაი გაივლის.
გამოსატანი მონაცემები: ერთადერთ სტრიქონში გამოიტანეთ ერთი მთელი რიცხვი –
ტრამვაის მინიმალური ტევადობა. დასაშვებია, რომ ის 0-იც იყოს.
28
განმარტება. თავიდან ტრამვაი ცარიელია და პირველ გაჩერებაზე მასში ადის 3 მგზავრი.
მეორე გაჩერებაზე ჩამოდის 2 და ადის 5 მგზავრი, ე.ი. ტრამვაი მოძრაობს 6 მგზავრით. მესამე
გაჩერებაზე ჩადის 4 და ამოდის 2 მგზავრი. ტრამვაი მიემგზავრება 4 მგზავრით, რომლებიც
ბოლო გაჩერებაზე ჩამოდიან. დროის არცერთ მომენტში მგზავრთა რაოდენობა არ აღემატებოდა
6-ს.
#include<iostream>
using namespace std;
int main(){
int n, a, b, i, k=0, k1=0;
cin>>n;
for(i=0;i<n;i++) {
cin>>a>>b;
k=k-a+b;
if(k>=k1)k1=k; }
cout<<k1;
}
29
#include <iostream>
using namespace std;
int n,x=0,y=0,z=0,s;
int main (){
cin>>n;
for (int i=0;i!=n;i++){
cin>>s;x+=s;cin>>s;y+=s;cin>>s;z+=s;}
if (x==0 && y==0 && z==0)cout<<"YES"; else cout<<"NO";
}
ანალიზი. შევასრულოთ ციკლი 1–დან n-მდე და ციკლის ყოველ ბიჯზე რაიმე ცვლადი
ერთით გავზარდოთ, ხოლო თუკი ციკლის ცვლადი 13-ის ჯერადია, იგივე ცვლადი დამატებით
გაიზარდოს ერთით.
#include <iostream>
using namespace std;
int i, ans=0;
int main (){
cin>>n;
for(int i=1;i<=n;i++){
ans++;
if(ans%13==0)ans++; }
cout<<ans;
}
30
ოპერატორები WHILE, DO/WHILE - ციკლი პირობით
#include <iostream>
using namespace std;
int n,k=0;
int main (){
cin>>n;
while (n>1){
k++;
if(n%2==0)n=n/2; else n=3*n+1;
cout<<n<<“ “; }
cout<<k;
}
#include <iostream>
using namespace std;
int a,c=1;
main(){
cin>>a;
while(a>c){
c=c*2; }
cout<<c/2<<” “<<c;
}
32
ამოცანა 39. 2–ის ხარისხების ჯამი
ცნობილია, რომ ნებისმიერი მთელი რიცხვი შეიძლება წარმოვადგინოთ როგორც 2–ის
ხარისხების ჯამი. დაწერეთ პროგრამა, რომელიც მოცემული მთელი N (0<N<30000)
რიცხვისთვის გამოიტანს კლებადობით დალაგებულ შესაბამის 2–ის ხარისხებს.
შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია ერთი მთელი რიცხვი N .
გამოსატანი მონაცემები: ერთადერთ სტრიქონში გამოიტანეთ შესაბამისი 2–ის ხარისხები.
33
განმარტება. რიცხვით ღერძზე სუპერკენგურუს მიერ განვლილი წერტილებია:
0, 1, 3, 7, 15, 14, 12, 8, 9, 11 – სულ 9 ნახტომი.
ანალიზი. ამოცანაში ერთგვარ სირთულეს ჰქმნის ის ფაქტი, რომ ნახტომები ორი
სხვადასხვა მიმართულებით სრულდება და კენგურუს მდებარეობის კოორდინატი ზოგჯერ
იზრდება, ხოლო ზოგჯერ – მცირდება. რადგან კენგურუ მიზანზე გადახტომის შემთხვევაში
ხტომებს კვლავ ერთეულოვანი ნახტომით იწყებს, შეგვიძლია ჩავთვალოთ მისი კოორდინატი
კვლავ 0–ია, ხოლო დაშორება მიზნამდე ჩავთვალოთ ახალი მიზნის კოორდინატად. მეტი
სიცხადისათვის განვიხილოთ ზემოთ მოყვანილი მაგალითი. მეოთხე ნახტომით კენგურუ
გადაახტება მიზანს და აღმოჩნდება წერტილში კოორდინატით 15. მისი დაშორება მიზნამდე
გახდა 4. ეს ნიშნავს, რომ შეგვიძლია კენგურუ შეგვიძლია წარმოვიდგინოთ ნულოვან
წერტილში, ხოლო მიზანი წარმოვიდგინოთ წერტილში 4 (უკვე შესრულებული ნახტომების
რაოდენობა, ცხადია, დავიმახსოვროთ).
#include <iostream>
using namespace std;
int a,c=1,x=0,ans;
main(){
cin>>a;
while(a>0){
ans++; x=x+c; c=c*2;
if(x>=a) {a=x-a; x=0;c=1;}
}
cout<<ans;
}
35
............... ............... .......|....... .C.|.C.|.C.|.C.
............... ............... ...C...|...C... ---C---|---C---
............... ............... .......|....... .C.|.C.|.C.|.C.
............... -> .......C....... -> -------C------- -> -------C-------
............... ............... .......|....... .C.|.C.|.C.|.C.
............... ............... ...C...|...C... ---C---|---C---
............... ............... .......|....... .C.|.C.|.C.|.C.
36
შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი
1 0
10 5
27 18
#include <iostream>
using namespace std;
main( ) {
int N, d = 1;
cin>>N;
do {
d = d + 1;
if( d*d > N ) d = N;
} while( N%d != 0 );
Cout<< N-N/d<<endl;
}
ანალიზი. იმ ფაქტს, რომ ვინი პუჰი ირჩევს ქილას ყველაზე მეტი თაფლით, ამოცანის
ამოხსნისათვის არავითარი მნიშვნელობა არ აქვს, რადგან იგივე ქილა სხვა თანმიმდევრობითაც
რომ აეღო, მაინც იმავე რაოდენობს თაფლს დაუტოვებდა მასში გოჭს. აქედან გამომდინარე
თითოეული ქილისათვის მხოლოდ ის არის დასადგენი, ვინი მისგან 3*k რაოდენობის თაფლს
შეჭამს, თუ x%k რაოდენობის თაფლს დატოვებს.
37
#include<iostream>
using namespace std;
int n,k,x, ans=0;
int main(){
cin>>n>>k;
while(n--){
cin>>x;
if(x>=3*k) ans+=x-3*k;
else ans+=x%k;
}
cout<<ans<<endl;
}
#include<iostream>
using namespace std;
long long m,num=1,pos=0,range=10,count_dig=1,k;
int main(){
cin>>k;
do {
while(num*num<range && pos<k)
{num++; pos+=count_dig;}
range*=10; count_dig++;
} while(pos<k);
m=(num-1)*(num-1);
while (pos-k>0) {
m/=10;pos--;}
cout<<m%10<<endl;
}
38
თეორიული ამოცანა
ევკლიდეს ალგორითმი
ევკლიდეს ალგორითმი პოულობს ორი რიცხვის უდიდეს საერთო გამყოფს. არსებობს ამ
ალგორითმის ორი ვარიანტი: სხვაობიანი და ნაშთიანი. სხვაობიანი ალგორითმი
დაფუძნებულია იმ ფაქტზე, რომ a და b (a>b) რიცხვების უდიდესი საერთო გამყოფი იგივეა რაც
a-b და b რიცხვების უდიდესი საერთო გამყოფი. ნაშთიანი ალგორითმი იგივე ლოგიკით
მუშაობს, ოღონდ სხვაობის ნაცვლად a%b ნაშთს იყენებს. თუკი a და b რიცხვები
ურთიერთმარტივები არიან, მაშინ ალგორითმი პასუხად 1-ს მიიღებს. ნაშთიანი ალგორითმი
სხვაობიანზე გაცილებით სწრაფი და ეფექტურია. ქვემოთ მოყვანილია ორივე მათგანის კოდი
და მუშაობა ბიჯების მიხედვით a=7222 და b=1727 რიცხვებისათვის.
#include <iostream>
using namespace std;
int a,b, r;
main(){
cin>>a>>b;
while (b!=0)
{r=a%b;
a=b; b=r;
}
cout<<a<<endl;
}
ამოცანა 48. მრგვალი რიცხვები
(ბულგარეთის ეროვნული ოლიმპიადა, 2010-11 წელი, 7-8 კლასი)
რიცხვებს, რომლებიც მხოლოდ 0–ებისა და 6–ების საშუალებით ჩაიწერება, მრგვალ
რიცხვებს უწოდებენ. მრგვალი რიცხვებისაგან შედგენილი ზრდადი მიმდევრობა ასე
გამოიყურება: 0, 6, 60, 66, 600, 606, 660, … და ა.შ.
დაწერეთ პროგრამა, რომელიც გამოითვლის K-ურ მრგვალ რიცხვს ზრდადობით
დალაგებულ მიმდევრობაში.
შესატანი მონაცემები: პირველ სტრიქონში ერთი მთელი რიცხვი – K (0<K≤1000).
გამოსატანი მონაცემები: ერთი მთელი რიცხვი – მრგვალი რიცხვების ზრდადობით
დალაგებულ მიმდევრობაში K ნომერზე მყოფი რიცხვი.
#include<iostream>
using namespace std;
int k, m;
long long st=1, res=0;
int main(){
cin>>k;
m=k-1;
while (m!=0) {
res+=6*st*(m%2);
st*=10; m/=2; }
cout<<res<<endl;
}
40
ამოცანა 49. მართკუთხედი
(ლატვიის ოლიმპიადა ინფორმატიკაში, მეორე ეტაპი, 1998)
ვილიბალდმა გადაწყიტა კვადრატებად დაჭრას n×m ზომის მართკუთხა უჯრედოვანი
ფურცელი. ის ერთი გაჭრით ღებულობს ფურცლიდან რაც შეიძლება დიდი ზომის კვადრატს,
შემდეგ ამ კვადრატს ინახავს, ხოლო ფურცლის დარჩენილ ნაწილზე იგივე მოქმედებას
იმეორებს. ვილიბალდი ამ ქმედებას იმეორებს მანამ, ვიდრე ფურცლის დარჩენილი ნაწილიც
კვადრატი არ გახდება
დაწერეთ პროგრამა, რომელიც მოცემული n და m (n<10000, m<10000)
რიცხვებისთვის გამოითვლის, თუ რამდენ კვადრატს მიიღებს ვილიბალდი აღწერილი გზით.
შესატანი მონაცემები: პირველ სტრიქონში ორი მთელი რიცხვი – n და m;
გამოსატანი მონაცემები: ერთი მთელი რიცხვი – მიღებული კვადრატების რაოდენობა.
#include<iostream>
using namespace std;
int N, M, Result=1;
main(){
cin>>N>>M;
While (N!=M){
If (N>M) N=N-M;
else M=M-N;
Result++;
}
cout<<Result;
}
41
შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი
4 2 2
3
7
2
0
7 1 1
4
2
1
0
#include <iostream>
using namespace std;
int main(){
int first, second, a, b, c, brp=0, brv=0;
cin>>first>>second;
a=first;b=second;
cin>>c;
do
{ if(a<b && c<b) brp++;
if(a>b && c>b) brv++;
a=b;b=c;cin>>c;
} while (c!=0);
c=first;
if(a<b && c<b) brp++;
if(a>b && c>b) brv++;
a=b;b=c;c=second;
if(a<b && c<b) brp++;
if(a>b && c>b) brv++;
cout << brp<<" "<<brv<<endl;
42
ორმაგი ციკლი
ორმაგი ციკლი, ანუ ერთი ციკლის შიგნით მეორე ციკლის ჩადგმა ხშირად არის საჭირო
სხვადასხვა ტიპის ამოცანების ამოხსნისას. პირველ მათგანს გარე ციკლს უწოდებენ, ხოლო
მეორეს (ჩადგმულს) – შიგა ციკლს. ასეთი კონსტრუქციის გამოყენებას რაიმე პრინციპული
თავისებურება არ გააჩნია, მაგრამ გამოცდილების მიღებამდე არცთუ იშვიათად ხდება
შეცდომების მიზეზი, ამიტომ ღირს ამ საკითხზე ყურადღების გამახვილება. განვიხილოთ
ორმაგი ციკლის მარტივი კოდი:
for (i = 1; i <= 2; i++){
for ( j = 5; j <= 7; j++) {
printf(“%d %d”,i,j); } }
პროგრამა ეკრანზე გამოიტანს:
1 5
1 6
1 7
2 5
2 6
2 7
ზოგადად რომ ვთქვათ, გარე ციკლის თითო ბიჯზე (იტერაციაზე) შიგა ციკლი მთლიანად
სრულდება. საბოლოოდ, გარე ციკლი მხოლოდ ერთხელ სრულდება, ხოლო შიგა ციკლი
იმდენჯერ სრულდება, რამდენჯერაც შეიცვლის მნიშვნელობას გარე ციკლის ცვლადი.
ყველაზე ხშირად შეცდომებამდე მივყავართ გარე და შიგა ციკლებში ერთ და იმავე
ციკლის ცვლადთა გამოყენებას.
#include <iostream>
int A,B;
main() {
cin>>A>> B;
for (i = 1; i <= A; i++){
for ( j = 1; j <= B; j++) {
cout<<”*”; }
cout<<endl; }
}
43
ამოცანა 52. დახატეთ მართკუთხა სამკუთხედი.
დაწერეთ პროგრამა, რომელიც მოცემული მთელი N (1 < N < 20) რიცხვისათვის “*”
სიმბოლოს საშუალებით გამოიტანს N კათეტის მქონე ტოლფერდა მართკუთხა სამკუთხედს.
შესატანი მონაცემები: ერთი მთელი რიცხვი – N.
გამოსატანი მონაცემები: შესაბამისი მართკუთხა სამკუთხედის გამოსახულება.
#include <iostream>
int A;
main() {
cin>>A;
for (i = 1; i <= A; i++){
for ( j = 1; j <= i; j++) {
cout<<”*”; }
cout<<endl; }
}
#include <iostream>
using namespace std;
int main() {
int r, s;
cin >> r >> s;
int a, b;
cin >> a >> b;
for (int i=0; i<r*a; ++i) {
for (int j=0; j<s*b; ++j)
cout << ((i/a+j/b)%2==0 ? 'X' : '.');
cout << endl;
}
}
#include <cstdio>
int n, i, sum = 0;
main( ) {
scanf("%d", &n);
for (i = 0; i <= n; i++)
for ( j = 0; j <= i; j++)
sum += i + j;
printf("%d\n", sum);
}
46
ანალიზი. ორმაგი ციკლის გარე ციკლში ვცვალოთ მონაწილეთა ნომრები, ხოლო შიგა
ციკლში გამოვთვალოთ შესაბამისი მონაწილის ქულათა ჯამი. შიგა ციკლის დასრულების
შემდეგ ორ ცვლადში დავიმახსოვროთ საუკეთესო შედეგი და მისი შესაბამისი ნომერი.
#include <cstdio>
using namespace std;
int main() {
int max_score = 0, winner = 0;
for ( int i=1; i<=5; ++i ) {
int sum = 0;
for ( int j=0; j<4; ++j ) {
int x;
scanf("%d", &x);
sum += x;
}
if ( sum > max_score ) {
max_score = sum;
winner = i;
}
}
printf("%d %d\n", winner, max_score);
return 0;
}
ანალიზი. თუკი ვეცდებით იმ 7–7 რიცხვის გადარჩევას, რომელთა ჯამიც 100–ს იძლევა,
მაშინ დაგვჭირდება შვიდმაგი ჩადგმული ციკლი. გაცილებით მარტივი იქნება დავადგინოთ
ცხრავე რიცხვის ჯამი და ვცადოთ იმ 2–2 რიცხვის გადარჩევა, რომელთა გამოკლებითაც
მიღებულ ჯამზე, 100–ს მივიღებთ. ამის ორგანიზება ორმაგი ციკლითაც შეიძლება.
47
#include <cstdio>
int main() {
int broj[9], suma = 0;
48
#include <iostream>
using namespace std;
int main(){
int x,t,a,b,da,db;
cin>>x>>t>>a>>b>>da>>db;
for (int i=0;i<t;i++)
for (int j=0;j<t;j++)
if ((x==a-i*da+b-j*db)||x==a-i*da||x==b-j*db||x==0) {cout<<"YES";
return 0;}
cout<<"NO";
return 0;
}
ამოცანა 58. ორი კვადრატის ჯამი
დაწერეთ პროგრამა, რომელიც დაადგენს, რამდენი განსხვავებული გზით შეგვიძლია
წარმოვადგინოთ მოცემული მთელი დადებითი რიცხვი ორი რიცხვის კვადრატების ჯამად.
შესატანი მონაცემები: ერთი მთელი რიცხვი – N (1<=N<30000).
გამოსატანი მონაცემები: შესაბამისი მართკუთხა სამკუთხედის გამოსახულება.
#include <iostream>
using namespace std;
int k=0,g,i,j,N;
int main(){
cin>>N;
for (i=1; i<N; i++)
for (j=1; j<N; j++)
if (i*i+j*j==N) k++;
cout<<k;
}
49
გამოსატანი მონაცემები: ერთი მთელი რიცხვი – დრო (წამებში), რომელიც დასჭირდება
ლუკას დისტანციის ბოლომდე მისასვლელად.
#include <iostream>
using namespace std;
main( ) {
int N, D, x=0, t=0, L, C, Z;
cin>>N>>D;
for( int i = 0; i < N; ++i ) {
cin>>L>>C>>Z;
t += L-x;
x = L;
while( t % (C+Z) < C ) ++t;
}
t += D-x;
x = D;
cout<<t;
}
50
ანალიზი. ორმაგი ციკლის გარე ციკლში მოვახდინოთ პირველი რიცხვის ციფრების
გენერაცია, ხოლო შიგა ციკლში მეორე რიცხვის ციფრები მივიღოთ. მიაქციეთ ყურადღება for
ციკლის ჩაწერის სინტაქსს. გარე ციკლში ციკლის ცვლადად თვითონ პირველი რიცხვია
აღებული და მისი საწყისი მნიშვნელობა საერთოდ არ მიეთითება. შიგა ციკლში ანალოგიურად
ვერ მოვიქცეოდით, რადგან პირველი რიცხვის თითოეული ციფრისათვის მეორე რიცხვი
ხელახლა უნდა დავშალოთ ციფრებად (პირველი რიცხვი მხოლოდ ერთხელ დაიშლება
ციფრებად). პირობის ნაწილში ციკლის ცვლადები არაფერს არ ედარებიან, რაც ნიშნავს, რომ
იგულისხმება მათი შედარება 0–თან.
#include <iostream>
using namespace std;
int a, b, i, sum;
main () {
cin>>a>>b;
for ( ; a ; a /= 10)
for (i = b; i ; i /= 10)
sum += (a % 10) * (i % 10);
cout<<sum;
}
51
ოპერატორები continue, break, goto, return
52
ამოცანა 61. უდიდესი გამყოფი
დაწერეთ პროგრამა, რომელიც მოცემული მთელი N (1 < N < 30000) რიცხვისათვის იპოვის
მის უდიდეს გამყოფს. თუ რიცხვი მარტივია, პროგრამამ გამოიტანოს 1.
შესატანი მონაცემები: ერთი მთელი რიცხვი N.
გამოსატანი მონაცემები: ერთი მთელი რიცხვი – N–ის უდიდესი გამყოფი.
შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი
34 17
11 1
119 17
63 21
ანალიზი. რადგან უდიდესი გამყოფია საძებნი, აჯობებს გამყოფები ვეძებოთ N/2–დან 1–
მდე და პირველივეს მოძებნის შემთხვევაში გამოვიდეთ ციკლიდან, რათა პროგრამამ დანარჩენი
გამყოფებიც არ დაბეჭდოს.
#include<iostream>
using namespace std;
int N,i;
main() {
cin >> N;
for (i=N/2; i>=1; i--)
if (N%i==0) {cout<<i<<endl; break;}
}
53
ამოცანა 63. ყველაზე გრძელი მანძილი – Long Distance Racing [Jeffrey Wang]
USACO, 2007/08 წლის თებერვლის შეჯიბრი, “ბრინჯაოს” დივიზიონი
ბესი ემზადება რბენაში შეჯიბრისათვის. სავარჯიშოდ მან შეარჩია ისეთი გზა,
რომელიც ყველანაირი ტიპის ლანდშაფტს შეიცავს. ბესი გარბის ამ გზაზე თავისი
ფერმიდან რაც შეიძლება შორს, ოღონდ გაითვალისწინებელი აქვს, რომ აუცილებლად
უნდა დაბრუნდეს უკან - ფერმაში M (1<=M<=10,000,000) წამის განმავლობაში.
ბესის მიერ შერჩეული გზა შედგება T (1<=T<=100,000) სეგმენტისაგან. ყველა
სეგმენტი ერთნაირი სიგრძისაა, ხოლო ტიპის მიხედვით შეიძლება იყოს
სამნაირი:აღმართი, დაღმართი და ვაკე. შემავალ მონაცემებში i-ური ნომრის მქონე
სეგმენტი აღიწერება ერთადერთი S_i სიმბოლოთი - u, f, ან d, რომლებიც
შესაბამისად აღნიშნავენ აღმართს, ვაკეს და დაღმართს.
აღმართის გადალახვას ბესი ანდომებს U (1<=U<=100) წამს, ვაკე სეგმენტის
გარბენისათვის სჭირდება F (1<=F<=100) წამი, ხოლო დაღმართის გადალახვისთვის - D
(1<=D<=100) წამი. უკან დაბრუნებისას აღმართი გადაიქცევა დაღმართად, დაღმართი -
აღმართად, ხოლო ვაკე სეგმენტის ტიპი არ იცვლება. გამოთვალეთ ყველაზე გრძელი
მანძილი (სეგმენტების რაოდენობა), რომელიც შეუძლია გაირბინოს ბესიმ, იმის
გათვალისწინებით, რომ დროულად დაბრუნდება ფერმაში.
შესატანი მონაცემები: პირველ სტრიქონში ხუთი მთელი რიცხვი: M, T, U, F, და D.
მომდევნო T სტრიქონიდან თითოეულში (i+1)-ე სტრიქონი შეიცავს i-ური სეგმენტის
ტიპს, გამოსახულს ერთადერთი S_i სიმბოლოთი.
გამოსატანი მონაცემები: ერთი მთელი რიცხვი - ყველაზე გრძელი მანძილი
(სეგმენტების რაოდენობა) რომელიც შეუძლია გაირბინოს ბესიმ, იმის
გათვალისწინებით, რომ დროულად დაბრუნდება ფერმაში.
განმარტება: მაგალითში ბესის აქვს 13 წამი შინ დასაბრუნებლად, ხოლო მთლიანი გზა
შედგება 5 სეგმენტისაგან. აღმართის გასარბენად ხარჯავს 3 წამს, ვაკეზე - 2 წამს და დაღმართზე
- 1 წამს. გზა ვიზუალურად ასე გამოიყურება:
_/\_
/
ბესის შეუძლია გაირბინოს სამი სეგმენტი და დაბრუნდეს უკან 3+2+3+1+2+1 = 12 წამში, რაც
ერთი წამით ნაკლებია დროის ლიმიტზე. თუკი ბესი მოინდომებს მომდევნო სეგმენტის
გარბენასაც, მაშინ უკან დროულად დაბრუნებას ვეღარ მოასწრებს.
54
#include<cstdio>
int M, T, U, F, D, A;
char c;
int main() {
scanf("%d %d %d %d %d",&M, &T, &U, &F, &D);
for(A=0;A<T;A++) {
scanf(" %c ",&c);
if(c=='f') M-=2*F; else M-=U+D;
if(M<0) break;
}
printf("%d\n",A);
return 0;
}
#include<iostream>
using namespace std;
int a,s,k,f=0,i;
main(){
cin>>a>>s;
for(i=0;i<a*2;i++){
cin>>k;
if(k==s || k==7-s) {f=1; break;}
}
if(f)cout<<"NO"<<endl; else cout<<"YES"<<endl;
}
56
შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი
3 17
123
#include <stdio.h>
#include <math.h>
int i, j, l, goal, n;
double x, y, frac, multiplier;
main () {
fscanf("%d", &l);
fscanf("%d", &goal);
for (multiplier = 1.0, i = 0; i < l; i++)
multiplier *= 10.0;
frac = goal/multiplier;
for(i=1; i<46000; i++){
n = (i+frac) * (i+frac) + 0.5;
j = x = sqrt ( (double) n);
x -= j;
j = multiplier * x;
if (j == goal) {
fprintf("%d\n", n);
exit (0);
}
}
fprintf("No solution\n");
return 0;
}
57
NO
განმარტება. 4-ს გააჩნია ზუსტად 3 გამყოფი: 1, 2 და 4, ამიტომ ის Т-მარტივია. 5-ს ორი
გამყოფი აქვს (1 და 5), ხოლო 6-ს - ოთხი (1, 2, 3, 6).
58
#include <stdio.h>
int x,y,i,j;
int main() {
scanf("%d%d",&x,&y);
for (i=0; x*100+y*10>=220; i++)
if (i%1>0) {
for (j=0; j<=2; j++)
if (x>=j && y>=22-j*10) { x-=j; y-=22-j*10; break; }
if (j>2) break;
} else {
for (j=2; j>=0; j--) if (x>=j && y>=22-j*10) { x-=j; y-=22-j*10; break; }
if (j<0) break;
}
if (i%1>0) puts("Ciel"); else puts("Hanako");
return 0;
}
ანალიზი. შევამოწმოთ რიცხვის ბოლო ციფრები თუ უდრის 144–ს, 14–ს ან 1–ს. დადებითი
პასუხის შემთხვევაში ეს ციფრები წავშალოთ და შემოწმება გავიმეოროთ. თუკი ასეთი პროცესის
შედეგად საწყისი რიცხვი განულდება, გამოვიტანოთ YES, წინააღმდეგ შემთხვევაში – NO.
#include<stdio.h>
int main(){
int n;
scanf("%d",&n);
while(n)
{
if(n%1000==144)n/=1000;
else if(n%100==14)n/=100;
else if(n%10==1)n/=10;
else break;
}
printf("%s\n",!n?"YES":"NO");
}
59
ამოცანა 69. რიგი კინოთეატრთან
http://codeforces.com/problemset/problem/349/ A
მართალია, ფილმი „კერკეტი კაკალი“ სულ ახალი გამოსულია, მაგრამ კინოთეატრის
სალაროებთან უკვე გაჩნდა n ადამიანისაგან შედგენილი უზარმაზარი რიგი. ყოველ მათგანს
ბილეთის შესაძენად აქვს თითო კუპიურა 100, 50 ან 25 რუბლის ღირებულებით. ბილეთი ღირს
25 რუბლი. შეძლებს თუ არა მოლარე, რომ რიგში მდგომ ყველა ადამიანს მიჰყიდოს ბილეთი და
დაუბრუნოს ხურდა, თუკ თავდაპირველად სალაროში ფული არ არის და მოლარე ბილეთებს
ჰყიდის მკაცრად რიგის მიხედვით?
შესატანი მონაცემები: პირველ სტრიქონში მოცემულია ერთი მთელი რიცხვი n (0 ≤n ≤ 105)
– ადამიანების რაოდენობა რიგში. მომდევნო სტრიქონში მოცემულია n ცალი მთელი რიცხვი,
რომელთაგან თითოეული 25-ის, 50-ის ან 100-ის ტოლია. რიცხვები თანმიმდევრობით
მოცემულია რიგის დასაწყისიდან (სალაროდან) რიგის დასასრულამდე.
გამოსატანი მონაცემები: გამოიტანეთ „YES“, თუკი მოლარე შეძლებს ყველა
ადამიანისათვის ბილეთის მიყიდვას და ხურდის დაბრუნებას. წინააღმდეგ შემთხვევაში
გამოიტანეთ „NO“.
#include<iostream>
using namespace std;
int main(){
float vp,vd,f,c,count=0,t,x=0;
cin>>vp>>vd>>t>>f>>c;
if(vd<=vp) {cout<<0; return 0; }
while(1){
x=x+t*vp+(vp*vp*t)/(vd-vp);
if(x<c)count++; else break;
t=f+2*x/vd;
}
cout<<int(count);
}
61
ერთგანზომილებიანი მასივები
ვთქვათ, დასამუშავებლად მოგვცეს რომელიმე ქალაქის ტემპერატურული მონაცემები 5
წლის მანძილზე. ეს 1800 რიცხვზე მეტია. ცხადია, რომ მათ შესანახად და მითუმეტეს
დასამუშავებლად ამდენივე ცვლადის აღწერა ძალზე მოუხერხებელია. ასეთ შემთხვევაში
ეფექტურია სპეციალური სტრუქტურის – მასივის გამოყენება, რომელიც საშუალებას იძლევა
ერთი სახელისა და სპეციალური ნომრის – ინდექსის საშუალებით ერთმანეთისაგან
განვასხვავოთ ათასობით და ზოგჯერ მილიონობით მონაცემი.
მასივები, ცვლადების მსგავსად, პროგრამაში წინასწარ უნდა აღიწეროს. მასივის
გამოცხადების ზოგადი ფორმა ასეთია:
ტიპი მასივის_სახელი [მასივის_ზომა];
მასივის ტიპთან და სახელთან მიმართება ხორციელდება იმავე პრინციპებით, როგორც ეს
ცვლადების მიმართ ხდება. მასივი ზომა კი ყოველთვის ცხადად უნდა იყოს გამოცხადებული,
რათა კოპილატორმა შეძლოს შესაბამისი უწყვეტი ადგილის გამოყოფა მეხსიერებაში. მასივის
ზომა პროგრამის მუშაობის განმავლობაში უცვლელი რჩება. აქ ხაზი უნდა გავუსვათ ერთ
გარემოებას, რომელიც ხშირად ხდება შეცდომის მიზეზი დამწყები პროგრამისტებისათვის:
მასივისათვის გამოსაყოფი მეხსიერება შეზღუდულია და ძალიან დიდი ზომის მასივების
გამოცხადებისას პროგრამა საერთოდ არ კომპილირდება. მეხსიერების შეზღუდვა ზოგჯერ
განპირობებულია სამუშაო გარემოს (რედაქტორის) მიერ, ზოგჯერ – კომპიუტერის
ოპერატიული მეხსიერების მიერ. საოლიმპიადო ამოცანებს კი ყოველთვის მიეთითებათ
მეხსიერების ლიმიტი. აქ გამოსავალი მარტივია: უნდა გამოვთვალოთ მასივის მიერ
დაკავებული მეხსიერების სიდიდე. ამისათვის მასივის ზომა უნდა გადავამრავლოთ მასივის
ტიპისათვის საჭირო ბაიტების რაოდენობაზე. მაგალითად, char a[1000]; მასივი
მეხსიერებაში დაიკავებს 1000 ბაიტს, რადგან char ტიპი ერთბაიტიანი მონაცემია, ხოლო
double temp[500000000] დაიკავებს 4 გიგაბაიტს, რადგან double ტიპი მეხსიერებაში 8
ბაიტს იკავებს.
მასივის ელემენტის წვდომა ხორციელდება მასივის სახელისა და ინდექსის საშუალებით.
ჩანაწერი temp[5]=17.4732; ნიშნავს, რომ მასივის მეხუთე ელემენტს მიენიჭა 17.4732.
C++–ში მასივის პირველი ელემენტის ინდექსი ყოველთვის 0–ის ტოლია, ამიტომ
ოპერატორი char a[100]; ნიშნავს, რომ შეიქმნა 100–ელემენტიანი მასივი a[0]–დან a[99]–
მდე, ხოლო ელემენტი a[100] არ არსებობს. ეს მომენტიც ხშირად ხდება შეცდომის მიზეზი
საწყის ეტაპზე, ისევე როგორც მასივის ელემენტის ინდექსისა და ელემენტის მნიშვნელობის
ურთიერთმიმართება.
ამოცანა 71. ყველაზე მაღალი ხე
ხუთკუნჭულამ კიდევ ერთხელ მოატყუა დევი და ახლა დასამალავ ადგილს ეძებს. მან
იცის, რომ დევმა თანამედროვე სუპერრადარი შეიძინა ხუთკუნჭულას მოსაძებნად და ადრე თუ
გვიან მაინც იპოვის მას. თუმცა ხუთკუნჭულას დიდად არ ანაღვლებს ეს ამბავი, რადგან დევმა
ვერა და ვერ ისწავლა ხეზე ასვლა, ამიტომ ხუთკუნჭულა ეძებს ყველაზე მაღალ ხეს დევის ერთ
მწკრივად განლაგებულ ხეივანში. ის დგას პირველ ხესთან და იცის ხეივნის ყველა ხის
სიმაღლე. ერთი ხიდან მეზობელ ხემდე მისვლას ხუთკუნჭულა ზუსტად 1 წამს ანდომებს.
გამოთვალეთ, რამდენ წამში მივა ხუთკუნჭულა ყველაზე მაღალ ხესთან.
შესატანი მონაცემები: პირველ სტრიქონში მოცემულია ერთი მთელი რიცხვი n (1≤n≤100) –
ხეივანში ხეების რაოდენობა. მეორე სტრიქონი შეიცავს n ცალ მთელ რიცხვს s1, s2,...,sn (1≤si ≤100),
სადაც si – i-ური ხის სიმაღლე ხეივანში.
გამოსატანი მონაცემები: ერთი მთელი რიცხვი – ყველაზე მაღალ ხესთან ხუთკუნჭულას
მისვლის დრო. პასუხის ერთადერთობა გარანტირებულია.
62
ანალიზი. ეს ამოცანა შეიძლება განვიხილოთ, როგორც მასივში მაქსიმუმის ძებნის ამოცანა,
ოღონდ გამოსატანია არა უშუალოდ მაქსიმუმის მნიშვნელობა, არამედ მისი ინდექსი მასივში.
მაქსიმუმის (და ანალოგიურად მინიმუმისაც) ძებნა მასივში ასე ხორციელდება: რაიმე ცვლადს
მივანიჭოთ მასივის პირველი ელემენტის მნიშვნელობა. დაწყებული მეორედან, მასივის ყველა
წევრი რიგრიგობით შევადაროთ ამ ცვლადს და თუ რომელიმე მათგანი მეტი იქნება ცვლადის
მიმდინარე მნიშვნელობაზე – შევცვალოთ ცვლადის მნიშვნელობა მასივის ამ ელემენტის
მნიშვნელობით. ამოცანაში ნაჩვენები მაგალითისათვის მაქსიმუმის მნიშვნელობა ასე
შეიცვლება:
მასივის ინდექსი 0 1 2 3 4 5 6 7
მასივის ელემენტი 129 341 86 209 532 61 600 98
მაქსიმუმი 129 341 341 341 532 532 600 600
#include <cstdio>
int N,i, mx,indexi,a[100];
main() {
scanf( "%d", &N);
for (i=0; i<N; i++)
scanf( "%d", &a[i]);
mx=a[0]; indexi=0;
for (i=1; i<N; i++){
if (a[i]>mx) {mx=a[i]; indexi=i;}
}
printf(“%d”,indexi);
}
63
შემოსატანი რიცხვების შესაბამის ინდექსებზე მყოფ ელემენტებს რიგრიგობით დავუმატოთ 1.
ამოცანის მაგალითის მიხედვით ჯერ მესამე ელემენტს დავუმატოთ 1, შემდეგ – პირველს,
შემდეგ – მეხუთეს და ა.შ. პროგრამულ კოდში ეს ხორციელდება შემოსატანი მონაცემების
წაკითხვასთან ერთად. საბოლოოდ, თითოეულ ინდექსზე მივიღებთ შესაბამისი ქულის
მოსვლათა რაოდენობას.
რაოდენობების დათვლის შემდეგ ერთი ციკლით ვიპოვოთ მასივის მაქსიმუმი, ხოლო
შემდეგ კიდევ ერთი ციკლით ამოვბეჭდოთ ის ინდექსები, რომლებზეც მყოფი ელემენტები
მაქსიმუმის ტოლია.
#include <iostream>
using namespace std;
#include <iostream>
using namespace std;
int N,i,ans,a[105];
64
main() {
cin>>N;
for (i=1; i<=N; i++){
cin>>a[i];}
a[0]=a[1];
for (i=1; i< N; i++)
if (a[i]<=a[i-1] && a[i]<a[i+1]) ans++;
cout<<ans;
}
#include <iostream>
using namespace std;
int N,i,ans,a[105];
main() {
cin>>N;
for (i=0; i<N; i++){
cin>>a[i];}
for (i=1; i<N–1; i++)
if (a[i]>a[i-1] && a[i]>a[i+1]) ans++;
cout<<ans;
}
65
ამოცანა 75. გრძელი არითმეტიკა
გამოთვალეთ N! (N! იკითხება, როგორც „N–ის ფაქტორიალი“ და წარმოადგენს ყველა
მთელი რიცხვის ნამრავლ 1–დან N–მდე).
შესატანი მონაცემები: მოცემულია ერთი მთელი რიცხვი N (1≤N≤1000).
გამოსატანი მონაცემები: ერთი მთელი რიცხვი – N–ის ფაქტორიალი.
66
ამოცანა 76. თამაში
(IOI, მერვე საერთაშორისო ოლიმპიადა, უნგრეთი, 1996 წელი)
განვიხილოთ შემდეგი თამაში ორი მოთამაშისათვის: სათამაშო დაფაზე დაწერილია
მთელი დადებითი რიცხვების მიმდევრობა. მოთამაშეები სვლებს აკეთებენ რიგ-რიგობით. სვლა
მდგომარეობს შემდეგში: მოთამაშე ირჩევს მიმდევრობის რომელიმე კიდურა წევრს (მარცხენას
ან მარჯვენას). არჩეული რიცხვი დაფიდან იშლება. თამაში დამთავრდება მაშინ, როცა დაფაზე
ყველა რიცხვი წაიშლება. პირველი მოთამაშე იმ შემთხვევაში გაიმარჯვებს, თუ მეორე
მოთამაშის მიერ არჩეული ჯამი მეტი არ იქნება მის მიერ არჩეული რიცხვების ჯამზე.
გაითვალისწინეთ, რომ მეორე მოთამაშე საუკეთესო ალგორითმით თამაშობს.
თამაშს ყოველთვის პირველი მოთამაშე იწყებს.
ცნობილია, რომ თუ დაფაზე თავიდან დაწერილი მიმდევრობის წევრთა რაოდენობა
ლუწია, მაშინ პირველ მოთამაშეს მოგების შანსი აქვს. დაწერეთ პროგრამა, რომელშიც
რეალიზებული იქნება პირველი მოთამაშის მომგებიანი სტრატეგია. საწყისი მიმდევრობის
წევრთა რაოდენობა N ყოველთვის ლუწია და 2<=N<=100.
67
#include<iostream>
using namespace std;
int a[1001],i,j,k,m,n;
int main(){
cin>>m>>n;
k=m;
for (i=0; i<=2*n; i++) {
m=k*10; k=m%n;
if (a[k]==2) break;
if (a[k]==1) {cout<<m/n; a[k]++;}
if (a[k]==0) a[k]++;
}
}
#include <cstdio>
main() {
int x, target[] = { 1, 1, 2, 2, 2, 8 };
for( int i = 0; i < 6; ++i ) {
scanf( "%d", &x );
if( i>0 ) printf( " " );
printf( "%d", target[i] - x );
}
printf( "\n" );
}
68
ამოცანა 79. მოდული
ხორვატიის ღია პირველობა ინფორმატიკაში (2006/07 წელი, შეჯიბრი 1)
მოცემულია ორი მთელი რიცხვი A და B. A მოდულით B ვუწოდოთ A–ს B–ზე გაყოფის
ნაშთს. მაგალითად, რიცხვებისათვის 7, 14, 27 და 38 მივიღებთ, რომ შესაბამისად 1, 2, 0 და 2,
მოდულით 3. დაწერეთ პროგრამა, რომელიც მოცემული 10 რიცხვისათვის გამოითვლის, თუ
რამდენ განსხვავებულ რიცხვს მივიღებთ, თითოეულ მათგანზე 42–ის მოდულით ჩატარებული
ოპერაციისას.
შესატანი მონაცემები: ათი სტრიქონიდან თითოეულში თითო მთელი რიცხვი არაუმეტეს
1000–ისა.
გამოსატანი მონაცემები: ერთადერთ სტრიქონში ერთი მთელი რიცხვი – განსხვავებული
რიცხვების რაოდენობა შემოსატან რიცხვებზე 42–ის მოდულით ჩატარებული ოპერაციისას.
#include <stdio.h>
int main() {
int i, sol = 0;
int mods[42] = {0};
for ( i=0; i<10; ++i ) {
int x;
scanf( "%d", &x );
mods[ x%42 ] = 1;
}
for ( i=0; i<42; ++i )
sol += mods[i];
printf( "%d\n", sol );
return 0;
}
69
ამოცანა 80. Bad Random Numbers - ცუდი შემთხვევითი რიცხვები [Richard V. Andree, 1965]
USACO, 2010 წლის დეკემბრის შეჯიბრი, “ბრინჯაოს” დივიზიონი
ბესი ცდილობს შემთხვევითი რიცხვების გენერაციას. მან იპოვა „შუა კვადრატების“
მეთოდის აღწერა, რომელიც აგენერირებს ფსევდოშემთხვევით რიცხვებს შემდეგი წესით:
– ავირჩიოთ საწყისი 4 ციფრი (1<=N<=9999);
– ავიღოთ შუა ორი ციფრი, როგორც რიცხვი;
– გამოვთვალოთ ამ რიცხვის კვადრატი;
– მიღებული შედეგი წარმოადგენს ახალ „შემთხვევით რიცხვს“.
მაგალითად:
რიცხვი შუა რიცხვი კვადრატი
7339 33 1089
1089 8 64
64 6 36
36 3 9
9 0 0
0 0 0
დირიხლეს პრინციპის თანახმად, ასეთი შემთხვევითი რიცხვები უნდა განმეორდნენ არა
უმეტეს 10000 იტერაციის შემდეგ. ზემოთ მოყვანილ მიმდევრობაში სულ 6 იტერაციაა. ყველა
მომდევნო რიცხვი 0–ის ტოლი იქნება.
შევნიშნოთ, რომ ზოგიერთი მიმდევრობები მეორდებიან უფრო რთული სახით.
მაგალითად, ქვემოთ ნაჩვენებ მიმდევრობაში განმეორება გვხვდება 576–ისა და 3249–ის სახით.
რიცხვი შუა რიცხვი კვადრატი
2245 24 576
576 57 3249
3249 24 576
დაადგინეთ, რამდენი შემთხვევითი რიცხვი იქნება გენერირებული, ვიდრე რიცხვები
განმეორებას არ დაიწყებენ. პირველ მაგალითში პასუხია 6–ია, ხოლო მეორეში – 3.
შესატანი მონაცემები: ერთადერთ სტრიქონში ერთი მთელი რიცხვი – N.
გამოსატანი მონაცემები: ერთი მთელი რიცხვი – იტერაციების რაოდენობა, ვიდრე
რიცხვები განმეორებას არ დაიწყებენ.
შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი
7339 6
#include <fstream>
using namespace std;
bool visited[10000];
int main() {
int N;
inp >> N;
int i = 0;
while (!visited[N]) {
visited[N] = true;
i++;
N = (N/10)%100;
N *= N;
}
outp << i << endl;
return 0;
}
70
ორგანზომილებიანი მასივები
0 1 2 3 4 5
0 12 31 8 28 23 19
1 9 27 32 10 12 22
2 16 24 41 17 6 39
71
ამოცანა 81. მთავარი დიაგონალები
იპოვეთ NxN (N<100) მასივის მთავარი დიაგონალების ჯამი.
შესატანი მონაცემები: პირველ სტრიქონში ერთი მთელი რიცხვი: N. მომდევნო N
სტრიქონიდან თითოეულში N ცალი მთელი რიცხვი დიაპაზონიდან 1..1000.
გამოსატანი მონაცემები: ორი მთელი რიცხვი - მთავარ დიაგონალებზე მდგომი
ელემენტების ჯამი. პირველად გამოიტანეთ დიაგონალი, რომელიც იწყება ზედა მარცხენა
კუთხეში და მთავრდება ქვედა მარჯვენა კუთხეში.
int n,i,j,sum1=0,sum2=0,arr[101][101];
main () {
cin>>n;
for (i = 1; i <=n; i++)
for (j = 1; j<=n; j++)
cin>>arr[i][j];
for (i = 1; i <=n; i++) {
sum1=sum1+arr[i][ i];
sum2=sum2+arr[i][ n+1-i] }
cout<<sum1<<” “<<sum2;
}
განმარტება. 21+10+9=40.
72
ანალიზი. დიაგონალის ზემოთ მდებარე ნებისმიერი ელემენტისათვის მარცხენა ინდექსი
მარჯვენაზე ნაკლებია, ხოლო დიაგონალის ქვემოთ მყოფი ელემენტებისათვის – პირიქით.
ელემენტების აჯამვა უშუალოდ მასივის ელემენტების კითხვის დროსაც შეიძლება.
#include <iostream>
using namespace std;
int n,i,j,sum=0,arr[101][101];
main () {
cin>>n;
for (i = 1; i <=n; i++) {
for (j = 1; j<=n; j++){
cin>>arr[i][j];
if (i<j) sum+=arr[i][j];
}
}
cout<<sum<<endl;
}
for(i=0;i<7;i++){
if (y[i]==3) {cout<<"FIRST";return 0;}
if (y[i]==-3){cout<<"SECOND";return 0;}}
cout<<"NO ONE";}
74
ამოცანა 85. რიცხვები დაფაზე
NxN (3<=N<=100) ზომის დაფაზე, რომელიც საჭადრაკო დაფის ანალოგიურადაა
დაყოფილი შავ და თეთრ უჯრედებად, ყოველ უჯრედში ჩაწერილია ორნიშნა რიცხვი. იპოვეთ
შავ უჯრედებში ჩაწერილი რიცხვების ჯამი, თუკი დაფის ზედა მარცხენა უჯრედი თეთრია.
შესატანი მონაცემები: პირველ სტრიქონში მოცემულია ერთი მთელი რიცხვი – N, მეორე
სტრიქონდან N+1 სტრიქონამდე თითოეულში მოცემულია N ცალი ორნიშნა რიცხვი.
გამოსატანი მონაცემები: ერთადერთ სტრიქონში ერთი მთელი რიცხვი – შავ უჯრედებში
ჩაწერილი რიცხვთა ჯამი.
შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი
3 177
12 25 78
19 38 91
37 42 63
ანალიზი. თითოეული შავი უჯრედის ინდექსთა ჯამი არის კენტი, ხოლო თითოეული
თეთრი უჯრედის ინდექსთა ჯამი – ლუწი. მასივიც ამ პირობით უნდა გადავამოწმოთ.
#include <iostream>
using namespace std;
int arr[101][101], i,j,m,n,x;
main () {
cin>>n;
for (i = 1; i<=n; i++)
for (j = 1; j<=n; j++)
cin>>arr[i][j];
for (i = 1; i<=n; i++)
for (j = 1; j<=n; j++)
if ((i+j)%2==1) x+=arr[i][j]
cout<<x;
}
75
#include <iostream>
#include <math.h>
int board[9][9], a1,b1,a2,b2;
main () {
cin>>a1>>b1;
cin>>a2>>b2;
if (a1==a2 || b1==b2 || abs(a1-a2)==abs(b1-b2)) cout<<”YES”;
else cout<<”NO”;
}
7
*
3 8
*
8 1 0
*
2 7 4 4
*
4 5 2 6 5
76
ანალიზი. მოცემული მაგალითისათვის ვთქვათ, ჩვენ უკვე შევარჩიეთ მაქსიმალური გზა
პირველ ოთხ სტრიქონში და მხოლოდ მეხუთე სტრიქონში დაგვრჩა რიცხვი ასარჩევი. თუკი
ჩვენ ვდგავართ მეოთხე სტრიქონის პირველ ელემენტზე (რიცხვი 2), მაშინ უნდა ავირჩიოთ 4-სა
და 5-ს შორის უდიდესი და მისკენ გავაგრძელოთ მოძრაობა, თუკი ვდგავართ მეოთხე
სტრიქონის მეორე ელემენტზე (რიცხვი 7), უნდა ავირჩიოთ უდიდესი 5-სა და 2-ს შორის და
მასზე გადავიდეთ და ა.შ. ცხადია, რომ ბოლოსწინა სტრიქონიდან სვლის გაკეთებისას
ნებისმიერ შემთხვევაში ორ ქვედა მეზობელს შორის უდიდესი უნდა ავირჩიოთ. აქედან
გამომდინარეობს, რომ თუკი ბოლოსწინა სტრიქონის თითოეულ ელემენტს წინასწარ
დავუმატებთ ორ ქვედა მეზობელთაგან უდიდესს და ბოლო სტრიქონს საერთოდ გავაუქმებთ –
მივიღებთ იმავე მაქსიმალური სიგრძის მქონე სამკუთხედს, როგორიც თავდაპირველად
გვქონდა მოცემული. თუკი ახალი სამკუთხედისთვისაც გავიმეორებთ იგივე ქმედებას,
სამკუთხედის ზომა კიდევ ერთი სტრიქონით შემცირდება და ასე გავაგრძელოთ მანამ, სანამ არ
დაგვრჩება მხოლოდ ზედა წვერო, რომელშიც უკანასკნელ ბიჯზე ჩაწერილი რიცხვი
წარმოადგენს ჩვენი ამოცანის ამონახსნს.
7 7
3 8 3 8
8 1 0 8 1 0
2 7 4 4 7 12 10 10
4 5 2 6 5 4 5 2 6 5
საწყისი სამკუთხედი ბიჯი 1
7 7 30
3 8 23 21 23 21
20 13 10 20 13 10 20 13 10
7 12 10 10 7 12 10 10 7 12 10 10
4 5 2 6 5 4 5 2 6 5 4 5 2 6 5
#include <stdio.h>
int A[350][350];
#define MAX(i,j) ((i) > (j) ? (i) : (j))
int main(void) {
int N, i, j;
fscanf ("%d", &N);
for (i=0; i<N; i++)
for (j=0; j<=i; j++)
scanf ("%d", &A[i][j]);
for (i=N-2; i>=0; i--)
for (j=0; j<=i; j++)
A[i][j] = A[i][j] + MAX(A[i+1][j], A[i+1][j+1]);
printf ("%d\n", A[0][0]);
}
77
შესატანი მონაცემები: პირველ სტრიქონში მოცემულია ორი მთელი რიცხვი – n და m
(1≤n≤1000, 1≤m≤min(n·n,105)) – უჯრედოვანი ფურცლის ზომა და გაფერადებული უჯრედების
რაოდენობა. მომდევნო m სტრიქონიდან თითოეულში მოცემულია გაფერადებული უჯრედის
აღწერა: i–ურ სტრიქონი შეიცავს ორ xi, yi (1≤xi,yi≤n) რიცხვს: i–ურ სვლაზე შეფერადებული
უჯრედის კოორდინატს.
სვლები შემოდის ნომრების ზრდადობის მიხედვით და არ მეორდება. უჯრედოვანი
ფურცელი გადანომრილია ზემოდან ქვემოთ და მარცხნიდან მარჯვნივ.
გამოსატანი მონაცემები: ერთი მთელი რიცხვი – სვლის მინიმალური ნომერი, რომლის
შემდეგაც ფურცელზე წარმოიქმნა 3×3 ზომის კვადრატი. თუ ასეთი სვლა არ არსებობს,
გამოიტანეთ –1.
#include<iostream>
using namespace std;
int n,m,x,y,a[1005][1005]={0},i,l,r;
int main(){
cin>>n>>m;
for(i=1;i<=m;i++){
cin>>x>>y;
for(l=x;l<x+3;l++){
for(r=y;r<y+3;r++){
a[l][r]++;
if(a[l][r]==9) {cout<<i; return 0;}
}
}
}
cout<<-1;
return 0;
}
78
ამოცანა 89. სპირალური სვლა – A spiral walk
USACO, 2011 წლის მარტის შეჯიბრი, “ბრინჯაოს” დივიზიონი
ძროხები სეირნობენ კვადრატულ საძოვარზე, რომელიც დაყოფილია N*N
(1<=N<=750) კვადრატად. ბესის გაასეირნოს ძროხები ყველაზე გრძელი მარშრუტით
ზედა მარცხენა კუთხიდან და ამასთან ყველა მცირე კვადრატი გაიაროს.
ბესიმ შეადგინა სპირალური მარშრუტი საათის ისრის მოძრაობის თანხვდენილი
მიმართულებით. დაწერეთ პროგრამა, რომელიც გამოიტანს განვლილი კვადრატების
თანმიმდევრობას. მაგალითად
1 2 3 1 2 3 4
8 9 4 12 13 14 5
7 6 5 11 16 15 6
10 9 8 7
#include <stdio.h>
int n,sum;
int a[755][755];
int main(){
scanf("%d",&n);
int i,j;
for (i = 0 ;i <= n ;i ++)
a[i][0] = 1,a[i][n + 1] = 1,a[0][i] = 1,a[n + 1][i] = 1;
i = 1 ,j = 1;
a[i][j] = 1;
sum = 1;
while (sum<n*n) {
while (!a[i][j + 1])
a[i][++ j] = ++ sum;
while (!a[i + 1][j])
a[++ i][j] = ++ sum;
while (!a[i][j - 1])
a[i][-- j] = ++ sum;
while (!a[i - 1][j])
a[-- i][j] = ++ sum;
}
return 0;
}
ამოცანა 90. კოსმოსური ცხრილი
http://codeforces.com/problemset/problem/222/ B
თავისუფალი მეტეორების ასოციაციას პრობლემა შეექმნა: მეტეორების მოძრაობის
აღმწერ პროგრამაში საჭიროა მოდულის ჩამატება, რომელიც დაამუშავებს მონაცემებს.
ინფორმაცია მეტეორების შესახებ მოცემულია n×m ცხრილის სახით. კოსმოსში მეტეორთა
გადაადგილების შესახებ მოდულს მიეწოდება შემდეგი მოთხოვნები:
• მოთხოვნა ცხრილის ორი სტრიქონისათვის ადგილის გაცვლის შესახებ;
• მოთხოვნა ცხრილის ორი სვეტისათვის ადგილის გაცვლის შესახებ;
• მოთხოვნა ცხრილის გარკვეულ უჯრედში ჩაწერილი რიცხვის შესახებ.
რადგან მოდულის დაწერა საჩქაროა, ეს საქმე თქვენ დაგევალათ.
შესატანი მონაცემები: პირველ სტრიქონში მოცემულია სამი მთელი რიცხვი: n, m და k
(1≤n,m≤1000, 1≤k≤500000) - ცხრილში სტრიქონების რაოდენობა, სვეტების რაოდენობა და
მოთხოვნათა რაოდენობა. მომდევნო n სტრიქონიდან თითოეულში ჩაწერილია m რიცხვი -
ცხრილის საწყისი მდგომარეობა. ცხრილში ყველა რიცხვი მთელია 1..106 დიაპაზონიდან.
მომდევნო სტრიქონიდან თითოეულში მოცემულია მოთხოვნები “si xi yi” ფორმატით,
სადაც si — ერთ-ერთია “с”, “r” ან “g” სიმბოლოებიდან, ხოლო xi,yi — ორი მთელი
რიცხვია.
• თუ si=”c”, მაშინ ეს არის მოთხოვნა xi და yi (1≤x,y≤m,x≠y) სვეტების გაცვლის
შესახებ;
• თუ si=”r”, მაშინ ეს არის მოთხოვნა xi და yi (1≤x,y≤m,x≠y) სტრიქონების
გაცვლის შესახებ;
• თუ si=”g”, მაშინ ეს არის მოთხოვნა xi სტრიქონსა და yi სვეტში (1≤x≤n,1≤y≤m)
მოთავსებული რიცხვის გამოტანა.
ჩათვალეთ, რომ სტრიქონები გადანომრილია ზემოდან ქვემოთ, ხოლო სვეტები -
მარცხნიდან მარჯვნივ.
გამოსატანი მონაცემები: ყოველი si=”g” მოთხოვნისათვის გამოიტანეთ თითო რიცხვი
თითო სტრიქონში. პასუხები გამოიტანეთ იმავე თანმიმდევრობით, როგორც ეს შემომავალ
მონაცემებშია.
80
ანალიზი: თუ ვიანგარიშებთ შესატანი მონაცემების მაქსიმალური მნიშვნელობებისათვის,
ცხადია, რომ პროცესის სიმულაცია (სტრიქონების ან სვეტების ელემენტებისათვის ადგილის
გაცვლა) ძალიან ბევრ ოპერაციას მოითხოვს. უფრო სწრაფი ამოხსნისათვის ერთგანზომილებიან
მასივებში ჩავწეროთ სტრიქონებისა და სვეტების ნომრები და შემდგომში მხოლოდ ამ ნომრებს
(ანუ მხოლოდ ორ–ორ რიცხვს) გავუცვალოთ ადგილები.
#include<iostream>
using namespace std;
int n,m,k,x,y,a[1020][1020],r[1020],c[1020];
char o;
int main()
{
cin>>n>>m>>k;
for(int i=1;i<=n;i++)
fo(j=1; j<=m; j++)
cin>>a[i][j];
for(int i=1;i<=n;i++)
r[i]=i;
for(int i=1;i<=m;i++)
c[i]=i;
for(int i=1;i<=k;i++)
{
cin>>o>>x>>y;
if(o=='r')
swap(r[x],r[y]);
else if(o=='c')
swap(c[x],c[y]);
else
cout<<a[r[x]][c[y]]<<endl;
}
}
81
ბიტური ოპერაციები
#include <iostream>
using namespace std;
int n,t,q,i;
main(){
cin>>n;
t=65536;
while (n/t==0) { t=t>>1;}
t=t<<1;
q=n;
i=1;
while (i<=t) {
n=n<<1;
n=(n+(n/t))%t;
i=i<<1;
if (n>q) q=n;
}
cout<<q;
system("PAUSE");
}
82
ამოცანა 92. მარსიანელის გენომი
პლანეტა მარსზე აღმოაჩინეს ცოცხალი არსებები, რომელთა გენომი N (3<=N<100000) კენტი
რაოდენობის გენისაგან შედგება. ყველა გენი გენომის შიგნით დუბლირებულია, გარდა ერთისა.
თითოეულ გენს მინიჭებული აქვს ნომერი დიაპაზონიდან 1..1,000,000,000.
დაწერეთ პროგრამა, რომელიც იპოვის დუბლის არმქონე გენს.
შესატანი მონაცემები: პირველ სტრიქონში მოცემულია ერთი მთელი კენტი რიცხვი – N,
მეორე სტრიქონში N ცალი რიცხვი – მარსიანელის გენის ნომრები..
გამოსატანი მონაცემები: ერთადერთ სტრიქონში ერთი მთელი რიცხვი – დუბლის არმქონე
გენის ნომერი.
შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი
7 29
12 25 25 78 29 12 78
ანალიზი. ვისარგებლოთ იმ ფაქტით, რომ a^a=0 და a^0= a. ანუ XOR ბიტური
ოპერაცია ნებისმიერი რიცხვისათვის საკუთარ თავთან 0–ს იძლევა. ამასთან, ბიტური
ოპერაციები ექვემდებარებიან ჯუფთებადობის კანონს და როგორი თანმიმდევრობითაც არ
უნდა ჩავატაროთ ოპერაციები რიცხვებზე, შედეგი არ შეიცვლება. აქედან გამომდინარე, ყველა
რიცხვის XOR–ის შემდეგ პირდაპირ საძებნ რიცხვს მივიღებთ.
#include<iostream>
using namespace std;
int n,t=0,i,a[100000];
main(){
cin>>n;
for(i=0;i<=n;i++){
cin>>a[i];
t=t^a[i];}
cout<<t;
}
83
ანალიზი. რადგან მასივის ელემენტთა რაოდენობა მცირეა, ორმაგი ციკლის გადავარჩიოთ
თანმიმდევრულად განლაგებული ელემენტების ყველა ვარიანტი (ვარიანტების რაოდენობა
10000–ზე მეტი არ იქნება) და მათ შორის უდიდესი პასუხი რაიმე ცვლადში დავიმახსოვროთ.
#include<iostream>
using namespace std;
int n,x[105],i,j,k,a;
main(){
cin>>n;
for(i=1; i<=n; i++)
cin>>x[i];
for(i=1; i<=n; i++){
k=x[i];
if(k>a) a=k;
for(j=i+1; j<=n; j++){
k=k^x[j];
if(k>a) a=k;
}
}
cout<<a<<endl;
}
main () {
int i, j, digits[7], sum, sum25=0;
84
for (i = 0; i < 7; i++) {
scanf ("%d", &digits[i]);
if (digits[i] == 0)
digits[i] = 10;
}
for (i = 0; i < 1 << 7; i++) {
sum = 0;
for (j = 0; j < 7; j++)
if (i & (1 << j))
sum += digits[j];
if (sum == 25)
sum25++;
}
printf ("%d\n", sum25);
}
85
ნათურები
1 2 3 4
ქმედება: O O O O O = off * = on
0 1 2 -> * * O O აინთო 1 და 2
0 2 4 -> * O * * 2..4 დიაპაზონში მდგომარეობები შეიცვალა
1 2 3 -> 1 2..3 დიაპაზონში ანთებულია 1 ნათურა
0 2 4 -> * * O O კვლავ შეიცვალა მდგომარეობები 2..4 დიაპაზონში
1 1 4 -> 2 1..4 დიაპაზონში ანთებულია 2 ნათურა
xor 0 1
0 01
1 10
#include <iostream>
Using namespace std;
int lights[505];
int n, m, i, a, b, command, sum, j;
main () {
cin>>n>>m;
for (i = 0; i < m; i++) {
cin>>command>>a>>b);
if (command == 1) {
sum = 0;
for (j = a; j <= b; j++)
sum += lights[j];
cout<<sum;
} else {
for (j = a; j <= b; j++)
lights[j]=lights[j]^1;
}
}
}
86
ფუნქციები
აქამდე ჩვენ ვწერდით პროგრამებს ერთიანი, ფუნქციონალურად უწყვეტი კოდით და
პროგრამა შედგებოდა მხოლოდ მთავარი main ფუნქციისაგან. მცირე ზომის პროგრამების
წერისას ეს პრობლემას არ ჰქმნის, მაგრამ თუ კოდის სიგრძე საკმაოდ დიდია, უმჯობესია ის
დავყოთ ცალკეულ, დამოუკიდებელ ნაწილებად და მთავარ პროგრამაში ფუნქციებად
წარმოვადგინოთ. პროგრამირების ასეთ სტილს „მოდულურ“ პროგრამირებას უწოდებენ, ხოლო
სხვადასხვა ენებში ფუნქციის ნაცვლად გამოიყენება ტერმინები „ქვეპროგრამა“, „პროცედურა“
და ა.შ. ფუნქციის ერთ–ერთ მთავარ ღირსებას წარმოადგენს ის მომენტი, რომ ერთხელ
შექმნილი ფუნქცია მრავალჯერადად შეიძლება გამოვიძახოთ პროგრამის სხვადასხვა
ადგილიდან. ეს საგრძნობლად ამცირებს პროგრამის კოდს და იოლად გასაგებს ხდის მას.
ზოგადად ფუნქციები შეიძლება ორ ჯგუფად: სტანდარტული და მომხმარებლის მიერ
შექმნილი. სტანდარტული ფუნქციების ჩამონათვალი წიგნს თან ერთვის თითოეული მათგანის
დანიშნულების აღწერით. სტანდარტულ ფუნქციას აუცილებლად უნდა ახლდეს შესაბამისი
include ფაილი.
მომხმარებლის (ანუ ჩვენს მიერ) შექმნილ ფუნქციებს აქვთ შემდეგი სახე:
ფუნქციის_ტიპი ფუნქციის_სახელი (ფუნქციის_პარამეტრები) {
ფუნქციის_ტანი;
}
ფუნქციის_ტიპი აღნიშნავს ფუნქციის მიერ დასაბრუნებელი მნიშვნელობის ტიპს. თუ
ფუნქცია მნიშვნელობას არ აბრუნებს, მაშინ ის განუსაზღვრელი, ანუ void ტიპისაა. ფუნქციის
სახელის შერჩევისას იგივე წესები ვრცელდება, როგორც იდენტიფიკატორის სახელზე.
ფუნქციისათვის გადასაცემი პარამეტრების ჩამონათვალი აუცილებლად მრგვალ ფრჩხილებში
უნდა იყოს მოქცეული. პარამეტრები ერთმანეთისაგან მძიმით გამოიყოფიან. ფუნქციის ტანი
აუცილებლად ფიგურულ ფრჩხილებშია ჩასმული.
ფუნქციის შიგნით აღწერილ ცვლადებს ლოკალურ ცვლადებს უწოდებენ და ისინი
წყვეტენ ფუნქციონირებას ფუნქციის დამთავრებისთანავე. ამრიგად, სხვადასხვა ფუნქციაში
შეიძლება გამოვიყენოთ ერთი და იგივე სახელის მქონე ლოკალური ცვლადები და ეს არანაირ
დაბრკოლებას არ შექმნის პროგრამის მუშაობისას. ცვლადები, რომლებიც აღწერილნი არიან
ყველა ფუნქციის გარეთ (მათ შორის, main ფუნქციის გარეთაც), მოქმედებენ პროგრამის
ნებისმიერ ნაწილში და მათ გლობალურ ცვლადებს უწოდებენ.
87
ამოცანა 96. ოთხი რიცხვი
(ხორვატიის ღია პირველობა ინფორმატიკაში, მესამე შეჯიბრი, 2007/08)
მირკომ ოთხი რიცხვისაგან არითმეტიკული პროგრესია შეადგინა. სხვაგვარად რომ
ვთქვათ, თუ ოთხ რიცხვს დავალაგებთ, განსხვავება მეზობელთა ნებისმიერ წყვილს შორის
ტოლია. როგორც ხშირად ხდება მირკომ ერთი რიცხვი დაკარგა, დანარჩენი სამის
თანმიმდევრობაც აერია. დაწერეთ პროგრამა, რომელიც მოცემული სამი რიცხვის მიხედვით,
იპოვის მეოთხეს.
შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია სამი რიცხვი –100–დან 100–მდე
დიაპაზონში. პასუხის არსებობა გარატირებულია. რამდენიმე პასუხის შემთხვევაში,
გამოიტანეთ ნებისმიერი.
გამოსატანი მონაცემები: ერთადერთ სტრიქონში ერთი მთელი რიცხვი – პროგრესიის
მეოთხე წევრი.
#include <cstdio>
int abs( int a ) {
if( a < 0 ) return -a;
return a;
}
#include <cstdio>
int f( int x, int a, int b ) {
return (x-1) % (a+b) < a;
}
int P, M, G;
scanf( "%d%d%d", &P, &M, &G );
solve( P, A, B, C, D );
solve( M, A, B, C, D );
solve( G, A, B, C, D );
return 0;
}
int A, B, C;
char hit[21][21][21];
main (){
scanf ("%d%d%d", &A, &B, &C);
visit (0, 0, C);
int i, j, first = 1;
for (i = 0; i < 21; i++)
for (j = 0; j < 21; j++)
if (hit[0][j][i]) {
if (first)
first = 0;
else
printf (" ");
printf ("%d", i);
}
printf ("\n");
return 0;
}
90
ამოცანა 99. ალმასისმაგვარი სიტყვები
(USACO, 2001 წლის ზამთარი, ”ნარინჯისფერი” დივიზიონი)
სიტყვას, რომელიც იწყება და მთავრდება ერთი და იგივე სიმბოლოთი უწოდებენ
ალმასისმაგვარს. მაგალითად ალმასისმაგვარია სიტყვა ”ENCODE”. ასეთი სიტყვებისათვის
გამოიყენება ალმასისმაგვარი ჩაწერა. მაგალითად:
E
NN
C C
O O
D D
E E
D D
O O
C C
N N
E
დაწერეთ პროგრამა, რომელიც ალმასისმაგვარ სიტყვას ალმასისმაგვარად ჩაწერს.
შემავალი მონაცემები: მთავრული სიმბოლოებით ჩაწერილი სიტყვა 3-დან 13
სიმბოლომდე, რომლის პირველი და ბოლო სიმბოლოები ემთხვევა.
გამომავალი მონაცემები: მოცემული სიტყვის ალმასისმაგვარი ჩანაწერი (თუ სიტყვა
შედგება N სიმბოლოსაგან, გამომავალი მონაცემი იქნება 2*N-1 სტრიქონი).
ანალიზი. ამოცანის ამოხსნისას მთავარია ზუსტად განისაზღვროს ჰარების რაოდენობა
ყოველ სტრიქონში, ამასთან ჰარები პირობითად ორ ნაწილად შეგვიძლია დავყოთ –
სიმბოლოებამდე ჩასაწერი ჰარები და სიმბოლოთა შორის ჩასაწერი ჰარები. პირველი ტიპის
ჰარების რაოდენობა იცვლება (N-1)-დან 0-მდე და შემდეგ 0-დან (N-1)-მდე. მეორე ტიპის ჰარები
პირველ და ბოლო სტრიქონებში საერთოდ არ გვხვდება, ხოლო მეორიდან მე-N-ე სტრიქონამდე
იზრდება 1-დან (2N-3)-მდე ბიჯით 2, ხოლო შემდეგ იმავე ბიჯით მცირდება 1-მდე. ჰარების
საბეჭდად შევქმნათ ფუნქცია printblank.
#include <stdio.h>
int printblank(int n) {
int i;
for (i = 0; i < n; i++)
printf(" ");
}
main () {
char word[20];
int len, i, j;
scanf("%s", word);
len = strlen(word);
for (i = 0; i <len; i++) {
printblank (len-1-i);
printf("%c", word[i]);
if (i > 0) {
printblank (2*i-1);
printf("%c", word[i]);
}
printf("\n");
}
for (i = len-2; i >= 0; i--) {
printblank (len-1-i);
printf("%c", word[i]);
91
if (i > 0) {
printblank (2*i-1);
printf("%c", word[i]);
}
printf("\n");
}
exit (0);
}
.
32 48 0 64 @ 80 P 96 ` 112 p
33 ! 49 1 65 A 81 Q 97 a 113 q
34 " 50 2 66 B 82 R 98 b 114 r
35 # 51 3 67 C 83 S 99 c 115 s
36 $ 52 4 68 D 84 T 100 d 116 t
37 % 53 5 69 E 85 U 101 e 117 u
38 & 54 6 70 F 86 V 102 f 118 v
39 ' 55 7 71 G 87 W 103 g 119 w
40 ( 56 8 72 H 88 X 104 h 120 x
41 ) 57 9 73 I 89 Y 105 i 121 y
42 * 58 : 74 J 90 Z 106 j 122 z
43 + 59 ; 75 K 91 [ 107 k 123 {
44 , 60 < 76 L 92 \ 108 l 124 |
45 - 61 = 77 M 93 ] 109 m 125 }
46 . 62 > 78 N 94 ^ 110 n 126 ~
47 / 63 ? 79 O 95 _ 111 o 127
#include<iostream>
using namespace std;
string s;
main(){
cin>>s;
if(s[0]>96) s[0]-=32;
cout<<s;
}
94
ამოცანა 102. ფეხბურთი
http://codeforces.ru/problemset/problem/43/A
ვასომ იპოვა ბერლანდიის 1910 წლის თასის გათამაშების ფინალური თამაშის ოქმი
ფეხბურთში. სამწუხაროდ, ოქმში არ ეწერა საბოლოო შედეგი, თუმცა იყო მატჩის
მიმდინარეობის აღწერა. აღწერა შედგება n ცალი სტრიქონისაგან, რომელთაგან თითოეულში
წერია იმ გუნდის სახელი, რომელმაც გოლი გაიტანა. დაწერეთ პროგრამა, რომელიც გაარკვევს
გამარჯვებული გუნდის სახელს. გარანტირებულია, რომ თამაში ფრედ არ დასრულებულა.
შესატანი მონაცემები: პირველ სტრიქონში მოცემულია ერთი მთელი რიცხვი
n (1≤n≤100) - სტრიქონების რაოდენობა ოქმში. თითოეულ სტრიქონში მოცემულია გოლის
გამტანის დასახელება, რომელიც წარმოადგენს ლათინური ანბანის ზედა რეგისტრის
სიმბოლოებისაგან შედგენილ არაცარიელ სიტყვას. გარანტირებულია, რომ ოქმში არ გვხვდება
ორზე მეტი დასახელების გუნდი.
გამოსატანი მონაცემები: ერთადერთ სტრიქონში გამოიტანეთ გამარჯვებული გუნდის
დასახელება. ფეხბურთში გამარჯვებულად ითვლება მეტი გოლის გამტანი გუნდი.
ანალიზი. რადგან თამაშში ერთი გოლი მაინც არის გასული, წავიკითხოთ პირველი
გოლის გამტანი გუნდის სახელი ციკლის გარეშე და ყველა დანარჩენი სტრიქონი მას
შევადაროთ. ამასთანავე, თუკი შევგვხდება პირველი სტრიქონისაგან განსხვავებული სახელი, ეს
იქნება მეორე გუნდის სახელი და ის ცალკე ცვლადში დავიმახსოვროთ.
#include<iostream>
using namespace std;
int a,b,c,d,i,j;
string m,n,k;
main () {
cin>>a>>n;
b=1;
for(i=1;i<=a-1;i++){
cin>>m;
if(n==m)b++; else {d++;k=m;}}
if(b>d) cout<<n; else cout<<k;
}
95
შესატანი მონაცემები: ლათინური მთავრული ასოებისაგან შედგენილი სიტყვა, რომლის
სიგრძეც არ აღემატება 254 სიმბოლოს.
გამოსატანი მონაცემები: Yes – თუ შემომავალი მონაცემი პალინდრომია და No –
წინააღმდეგ შემთხვევაში.
#include <iostream>
#include <string>
using namespace std;
int i,j=0,n;
string s;
main () {
cin>>s;
n=s.size ();
for(i=0;i<n/2;i++){
if (s[i]!=s[n-i-1]) j=1;}
if(j==0) cout<<"YES"; else cout<<"NO";
}
#include <iostream>
#include <string>
using namespace std;
int i,j=1,n,ans;
string s;
main () {
96
cin>>s;
n=s.size();
for(i=n-1;i>=0;i--){
ans=ans+j*((int)s[i]-48);
j=j*2;}
cout<<ans;
}
#include <iostream>
#include <string>
using namespace std;
int n,k;
string s;
main(){
cin>>n;
for(int i=0;i<n;++i)
{
cin>>s;
k=s.size();
if (k>10) cout<<s[0]<<k-2<<s[k-1];
else cout<<s; cout<<endl;}
}
97
ამოცანა 106. დაზიანებული კლავიატურა
კომპიუტერის კლავიატურა იმგვარადაა დაზიანებული, რომ ზოგჯერ კლავიშზე ხელის
დაჭერისას ერთის ნაცლად რამდენიმე სიმბოლოს ბეჭდავს. ცნობილია, რომ ამ კლავიატურიდან
შეტანილ ტექსტში ერთმანეთის მეზობლად ერთნაირი სიმბოლოები არ გვხდება. დაწერეთ
პროგრამა, რომელიც შეასწორებს ტექსტს და წაშლის მასში ზედმეტ სიმბოლოებს.
შესატანი მონაცემები: ლათინური დაბალი რეგისტრის ასოებისაგან შედგენილი სიტყვა,
რომლის სიგრძეც არ აღემატება 250 სიმბოლოს.
გამოსატანი მონაცემები: შესწორებული ტექსტი.
#include <iostream>
#include <string>
using namespace std;
int i,j=1,n,ans;
string s;
main () {
cin>>s;
n=s.size();
for(i=n-1;i>=1;i--){
if (s[i]==s[i-1]) s.erase(i,1);}
cout<<s;
}
ამოცანა 107. კოდის კორექცია
კავშირგაბმულობის რომელიღაც არხით გადაეცემა შეტყობინება, რომელსაც აქვს 0-ებისა
და 1-ებისაგან შედგენილი მიმდევრობის სახე. არხში არსებული ხარვეზების გამო ზოგიერთი
სიგნალი შესაძლოა შეცდომით იქნას მიღებული: 0 აღქმული იქნას 1-ად და პირიქით.
სიგნალების გადაცემის საიმედოობის გასაზრდელად გადაწყდა, რომ თითოეული სიგნალი
სამჯერ გაიგზავნოს. გადამცემი 1-ის ნაცვლად აგზავნის 111-ს, ხოლო 0-ის ნაცვლად 000-ს.
დაწერეთ პროგრამა, რომელიც აღადგენს საწყის შეტყობინებას. რადგან გადაცემისას
მოსალოდნელი იყო ხარვეზები, ციფრთა ყოველი სამეულის ნაცვლად პროგრამამ უნდა
გამოიტანოს ის ციფრი, რომელიც ამ სამეულში ორჯერ მაინც გვხვდება.
შესატანი მონაცემები: მოცემულია ერთადერთი სტრიქონი, რომელიც შედგება “0”-ებისა
და “1”-ებისაგან. სტრიქონის სიგრძე 3-ის ჯერადი რიცხვია, მეტია 2-ზე და ნაკლებია 760-ზე.
გამოსატანი მონაცემები: ერთადერთ სტრიქონში გამოიტანეთ გაშიფრული შეტყობინება.
98
#include <iostream>
#include <string>
using namespace std;
int i,j=1,n,k;
string s;
main () {
cin>>s;
n=s.size();
for(i=0;i<n;i=i+3) {
k=s[i]-48+s[i+1]-48+s[2]-48;
if (k>1) cout<<1; else cout<<0; }
}
განმარტება. პირველ მაგალითში არის მხოლოდ ერთი ბრძანება «H», რომელიც გამოიტანს
ბეჭდვაზე «Hello, World!». მეორე მაგალითში არცერთი სიმბოლო არ წარმოადგენს ბრძანებას.
#include<stdio.h>
int main(){
char k;
while((k=getchar())!='\n')
if(k=='H'||k=='Q'||k=='9'){printf("YES");return 0;}
printf("NO");
}
99
ამოცანა 184. მძიმეების ჩამატება – Adding Commas [Traditional, 2010]
USACO 2010/11 წლის დეკემბრის შეჯიბრი, “ბრინჯაოს” დივიზიონი
ბესი მუშაობს დიდ N (1<=N<=2,000,000,000) რიცხვებთან. მაგალითად, 153920529.
ბესის ესმის, რომ რიცხვების წაკითხვა უფრო ადვილია, თუ მას, მარჯვნიდან მარცხნივ,
დავყოფთ სამციფრიან ჯგუფებად: 153,920,529.
დაწერეთ პროგრამა, რომელი გააკეთებს მძიმეების ჩამატებას რიცხვში.
შესატანი მონაცემები: ერთი მთელი რიცხვი – N.
გამოსატანი მონაცემები: ერთი მთელი რიცხვი – N, რომელიც მძიმეებით დაყოფილია
სამციფრიან ჯგუფებად.
შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი
153920529 153,920,529
#include <iostream>
using namespace std;
int main() {
string number;
cin >> number;
cout << number[0];
for (int i=1; i < number.length(); i++) {
if ((number.length()-i) % 3 == 0)
cout << ',';
cout << number[i];
}
cout << endl;
}
100
ანალიზი. დავადგინოთ სტრიქონის სიგრძე და ერთი ციკლის საშუალებით დავთვალოთ
მასში შემავალი თითოეული სიმბოლოს რაოდენობა. ამისათვის გამოვიყენოთ ის თვისება, რომ
ყოველ სიმბოლოს (მათ შორის ციფრებსაც) შეესაბამება ორიგინალური კოდი. სწორედ ამ კოდის
შესაბამის ინდექსზე ავჯამოთ სიმბოლოთა რაოდენობა. ამის შემდეგ, მეორე ციკლის
საშუალებით გამოვთვალოთ ამოცანის პასუხი.
#include <stdio.h>
#include <string.h>
int n,i;
char s[100005];
long long a[270],r;
int main() {
scanf("%s",s); n=strlen(s);
for (i=0; i<n; i++) a[s[i]]++;
for (i=0; i<270; i++) r+=a[i]*a[i];
printf("%I64d\n",r);
}
101
შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი
atob forward
a
b
aaacaaa both
aca
aa
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 100010
using namespace std;
char s1[N],s2[N],a[110],b[110];
const char sol[4][20]={"fantasy","forward","backward","both"};
int main(){
int ans=0;
scanf("%s %s %s",s1,a,b);
strcpy(s2,s1);
reverse(s2,s2+strlen(s2));
if ( strstr(s1,a) && strstr(s1,a)+strlen(a)<s1+strlen(s1) &&
strstr(strstr(s1,a)+strlen(a),b) ) ans|=1;
if ( strstr(s2,a) && strstr(s2,a)+strlen(a)<s2+strlen(s2) &&
strstr(strstr(s2,a)+strlen(a),b) ) ans|=2;
puts(sol[ans]);
return 0;
}
102
სორტირება. მინიმალური და მაქსიმალური
ამოცანა 111. ყანჩები
რუსეთის ოლიმპიადა, რეგიონული ეტაპი, 2012
პეტიამ და მაშამ ზოოპარკში გაისეირნეს. პეტიას ყველაზე მეტად ყანჩები
მოეწონა. ის აღფრთოვანდა ყანჩების უნარით – დაეძინათ ცალ ფეხზე მდგომებს.
ვოლიერში რამდენიმე ყანჩაა. ზოგი დგას ორ ფეხზე, ზოგი – ცალ ფეხზე. როცა
ყანჩა დგას ცალ ფეხზე, მეორე ფეხი არ ჩანს. პეტიამ დაითვალა ყველა ყანჩის ფეხები
(რომლებიც ჩანდა) და გამოვიდა a რაოდენობა. რამდენიმე წუთის შემდეგ ვოლიერთან მაშა
მივიდა. ამ დროში ზოგიერთ ყანჩას შეეძლო მდგომარეობის შეცვლა, ამიტომ პეტიამ სთხოვა,
ხელახლა დაეთვალა ფეხები. მაშამ მიიღო რიცხვი b.
ზოოპარკიდან გამოსული პეტია და მაშა დაინტერესდნენ, რამდენი ყანჩა იყო ვოლიერში.
ბავშვები მალე მიხვდნენ, რომ ამ რიცხვის ცალსახად განსაზღვრა ყოველთვის არ მოხერხდება.
ახლა მათ სურთ გაიგონ, რა მინიმალური და მაქსიმალური რაოდენობის ყანჩა შეიძლება
ყოფილიყო ვოლიერში. დაწერეთ პროგრამა, რომელიც მოცემული a და b რიცხვების მიხედვით
გაარკვევს ამ საკითხს.
შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია ორი მთელი რიცხვი – a და b
(1≤a≤109, 1≤b≤109).
გამოსატანი მონაცემები: ერთადერთ სტრიქონში გამოიტანეთ ორი, ჰარით გაყოფილი
რიცხვი: ყანჩების შესაძლო მინიმალური და მაქსიმალური რაოდენობა ვოლიერში. პასუხის
არსებობა გარანტირებულია.
#include <iostream>
#include <algorithm>
using namespace std;
int main(){
int a, b;
cin >> a >> b;
cout << (max(a, b) + 1) / 2 << " " << min(a, b) << endl;
}
return 0;
}
104
ამოცანა 113.ისტორია
http://codeforces.com/problemset/problem/144/C
პოლიკარპს ძალიან უყვარს სწავლა და ყოველთვის კეთილსინდისიერად ასრულებს
დავალებებს. ის ძალიან განიცდის, რომ ბოლო ხანს მას პრობლემები შეექმნა ისტორიის საგანში.
ცნობილია, რომ ისტორიაში მოხდა ზუსტად n მოვლენა: i–ური მოვლენა გრძელდებოდა ai
წლიდან bi წლამდე ამ წლების ჩათვლით (ai<bi). ეს თარიღები პოლიკარპმა ზეპირად იცის,
მაგრამ მასწავლებელმა დაავალა ყოველი მოვლენისათვის დაადგინოს, მოიცავდა თუ არა მას
რომელიმე სხვა მოვლენა. j–ური მოვლენა მოიცავს i–ურ მოვლენას, თუ aj<ai და bi<bj.
თქვენ უფრო მარტივი დავალება გეძლევათ: დაადგინეთ მოვლენათა რაოდენობა, რომელსაც
რომელიმე სხვა მოვლენა შეიცავს.
შესატანი მონაცემები: პირველ სტრიქონში მოცემულია მთელი რიცხვი n (1≤n≤105) –
მოვლენათა რაოდენობა. მომდევნო n სტრიქონიდან თითოეულში აღწერილია თითო
ისტორიული მოვლენა. i+1 სტრიქონში ჩაწერილია ორი მთელი რიცხვი ai და bi
(1≤ai<bi≤109) — i-ური მოვლენის დასაწყისი და დასასრული. არცერთი მოვლენა არ იწყება
და არ მთავრდება ერთსა და იმავე წელს, ანუ ai≠aj, ai≠bj, bi≠aj, bi≠bj ნებისმიერი i,j
(სადაც i≠j).
გამოსატანი მონაცემები: გამოიტანეთ ერთი მთელი რიცხვი – ამოცანის პასუხი.
#include<iostream>
#include<algorithm>
using namespace std;
int main(){
long long cur=0,i,j,n,x,y,kol=0;
cin>>n;
pair <int ,int> q[n];
for(i=0;i<n;i++){
cin>>q[i].first>>q[i].second;
}
sort(q,q+n);
for(i=0;i<n;i++){
if(q[i].second<cur)kol++;else cur=q[i].second;
}
cout<<kol;
}
105
ამოცანა 114. არითმეტიკული პროგრესია
მოცემულია n მთელი რიცხვი. დაწერეთ პროგრამა, რომელიც განსაზღვრავს ადგენენ თუ
არა ისინი არითმეტიკულ პროგრესიას მათი რაიმე თანმიმდევრობით დალაგებისას.
შესატანი მონაცემები: პირველ სტრიქონში მოცემულია ერთი მთელი რიცხვი – n
(1≤n≤105). მეორე სტრიქონში მოცემულია n ცალი მთელი რიცხვი 1..109 დიაპაზონიდან.
გამოსატანი მონაცემები: გამოიტანეთ სიტყვა YES, თუკი მოცემული რიცხვები რაიმე
თანმიმდევრობით ადგენენ არითმეტიკულ პროგრესიას. წინააღმდეგ შემთხვევაში გამოიტანეთ
სიტყვა NO.
106
განმარტება. პირველ მაგალითში მესამე დღის შემდეგ დაიშლებაა მეორე ფილა, რის
შემდეგაც შესაძლებელი იქნება სეირნობა მარშრუტით 1→3→4. მეხუთე დღის შემდეგ პირველ
ბოლო ფილებს შორის მიყოლებით ორი ფილა იქნება დაშლილი, რაზე გადახტომა უკვე
შეუძლებელი იქნება.
მეორე მაგალითში მეხუთე დღის ჩათვლით ვარგისი იქნება მარშრუტი 1→3→5. მეხუთე
დღეს დაიშლება ბოლო ფილა, რის შემდეგაც სეირნობა შეწყდება.
#include <iostream>
#include <algorithm>
using namespace std;
int a,a1,b,c,i,n;
int main()
{
cin>>n>>a; a1=a;
if (n==1) {cout<<a; r0}
cin>>b;
if (n==2) {cout<<min(a,b); r0}
for (i=3;i<=n;i++) {cin>>c; if(c>(max(a,b))) c=max(a,b); a=b; b=c;}
cout<<min(a1,c);
return 0;
}
#include<iostream>
using namespace std;
int n,i,j,t,res,a[1001];
int main(){
cin>>n;
for(i=0;i<n;i++)
cin>>a[i];
for(i=0;i<n;i++){
t=0;
for(j=i;j>=1;j--)
if(a[j]>=a[j-1]) t++; else break;
for(j=i+1;j<n;j++)
if(a[j-1]>=a[j]) t++; else break;
res=max(res,t+1);
}
cout<<res<<endl;
}
#include <cstdio>
#include <cstdlib>
#include <cmath>
109
#include <algorithm>
#include <stdio.h>
#include <stdlib.h>
main() {
110
int n, s, l[20000], i, j, count;
111
ანალიზი. რადგან ბესი ყოველთვის მიდის იმ ახალ წერტილში, რომელიც ყველაზე ახლოსაა
საწყის წერტილთან, დავასორტიროთ „წარმტაცი ადგილების“ კოორდინატების აბსოლუტური
მნიშვნელობები და განვიხილოთ ისინი თანმიმდევრულად.
#include <stdio.h>
#include <stdlib.h>
int list[50000];
main() {
int T, N, i, j, bessloc, nvisit, timevisit;
/* start visiting: */
bessloc = 0;
nvisit = 0;
timevisit = 0;
for (i = 0; i < N; i++) {
timevisit += abs(list[i] - bessloc);
if (timevisit > T) break;
nvisit++;
bessloc = list[i];
}
printf ("%d\n", nvisit);
}
112
სტრუქტურები
წინა თავებში განვიხილეთ მასივები, სადაც ელემენტებში ვინახავდით ერთი და იმავე
ტიპის ინფორმაციას. პრაქტიკაში ხშირია შემთხვევა, როცა აუცილებელია სხვადასხვა ტიპის
მონაცემთა დაჯგუფება. მაგალითად, ბანკის მეანაბრეთა მონაცემები: სახელი და გვარი (string
ტიპის ცვლადი), დაბადების წელი (int ტიპის ცვლადი), ანაბარზე არსებული თანხა (float ან
double ტიპის ცვლადი). ცხადია, რომ ამ მონაცემების შენახვა 3 სხვადასხვა მასივშიც შეიძლება,
მაგრამ ეს ძალიან გაართულებდა მათ დამუშავებას – რომელიმე მათგანის დასორტირების
შემთხვევაში პარალელურად მოგვიწევდა ცვლილებების განხორციელება სამივე მასივში.
ასეთი პრობლემების გადასაწყვეტად პროგრამირების ენებში არსებობს სპეციალური
სტრუქტურა, რომელიც საშუალებას იძლევა ერთად შევინახოთ ინფორმაცია სხვადასხვა ტიპის
ცვლადების შესახებ. C/C++–ში ასეთ ბრძანებას წარმოადგენს struct. იგი წარმოადგენს შაბლონს,
რომლის მიხედვითაც პროგრამაში შეიძლება გამოვაცხადოთ ცვლადები და მასივები. struct
გასაღები სიტყვის შემდეგ მოდის შაბლონის სახელი და მარცხენა ფიგურული ფრჩხილები,
რომელთა შორის ჩამოთვლილია შაბლონის ელემენტთა ტიპები და სახელები:
struct შაბლონის სახელი
{
int ელემენტის სახელი1 ;
float ელემენტის სახელი2; } ცვლადის სახელი;
}
ზემოთ მოყვანილი მაგალითის შესაბამისი სტრუქტურა 1000 ადამიანისათვის იქნება:
struct deposit{
string name;
int year;
float money;
} people[1000];
113
ამოცანა 121. დრაკონები
http://codeforces.com/problemset/problem/230A
კირიტო გადავიდა MMORPG–ის მორიგ ეტაპზე. თამაშის გასაგრძელებლად მას სჭირდება
ამ ეტაპზე არსებული n დრაკონის დამარცხება. კირიტოსაც და დრაკონებსაც გააჩნიათ ძალა,
რომელიც გამოსახება მთელი რიცხვით. ორ მოწინააღმდეგეს შორის იმარჯვებს ის, ვისაც მეტი
ძალა აქვს. კირიტოს თავდაპირველი ძალა s–ის ტოლია. თუკი კირიტო ებრძვის i-ურ (1 ≤ i ≤ n)
დრაკონს და მისი ძალა არ აღემატება დრაკონის xi ძალას, მაშინ კირიტო იღუპება. თუკი
კირიტოს ძალა აღემატება დრაკონის ძალას, მაშინ ის ამარცხებს დრაკონს და იღებს ბონუსს –
მისი ძალა იზრდება yi–ით.
კირიტოს შეუძლია დრაკონებთან ბრძოლა ნებისმიერი თანმიმდევრობით. გაარკვიეთ,
გადავა თუ არა ის მომდევნო ეტაპზე, ანუ დაამარცხებს თუ არა ყველა დრაკონს ისე, რომ თავად
არცერთხელ არ დამარცხდეს.
შესატანი მონაცემები: პირველ სტრიქონში მოცემულია ორი მთელი რიცხვი: s და n
(1≤s≤104, 1≤n≤103). მომდევნო n სტრიქონიდან ყოველი i-ური სტრიქონი შეიცავს ორ მთელ
რიცხვს xi და yi (1≤xi≤104, 0≤yi ≤104) – i-ური დრაკონის ძალა და ბონუსი მასზე გამარჯვებისათვის.
გამოსატანი მონაცემები: ერთადერთ სტრიქონში გამოიტანეთ «YES», თუ კირიტო გადავა
მომდევნო ეტაპზე და «NO» – თუკი ვერ გადავა.
#include<iostream>
#include<algorithm>
using namespace std;
int a,s,f,g,h,j,k,l,i,n,m;
pair<int,int> d[10002];
main(){
cin>>m>>n;
for(i=0;i<n;i++){
cin>>d[i].first>>d[i].second;}
sort(d,d+n);
for(i=0;i<n;i++){
if(d[i].first<m) m=m+d[i].second; else {cout<<"NO";return 0;}}
cout<<"YES";
}
114
მოთამაშე რამდენიმეა. თამაში თითოეულ ფსონზე მოთამაშე იგებს ან აგებს ქულათა გარკვეულ
რაოდენობას. თამაში მსვლელობის ჩანაწერში ეს აღინიშნება ფორმატით «name score», სადაც
name ამ მოთამაშის სახელია, ხოლო score – მოთამაშის მიერ დაგროვებული ქულების
რაოდენობა. თუკი score უარყოფითი რიცხვია, ეს ნიშნავს რომ მოთამაშემ ამ ფსონზე წააგო. თუ
რამდენიმე მოთამაშე აგროვებს მაქსიმალურ ქულას (ვთქვათ, ეს ქულაა m), მაშინ
გამარჯვებულად ცხადდება ის მოთამაშე, რომელმაც პირველმა (ანუ ყველაზე ადრე) მოაგროვა
m ქულა. თამაშის დაწყების წინ თითოეულ მოთამაშეს 0 ქულა აქვს. გარანტირებულია, რომ
თამაშის დასრულების მომენტში ერთ მოთამაშეს მაინც აქვს დადებითი ქულა.
შესატანი მონაცემების ფორმატი: პირველ სტრიქონში მოცემულია ერთი მთელი რიცხვი
n (1≤n≤1000) – ნათამაშევ ფსონთა რაოდენობა. მომდევნო n სტრიქონიდან
თითოეულში ფსონთა შედგები ფორმატით „name score“ ქრონოლოგიური
მიმდევრობით, სადაც name არის ლათინური დაბალი რეგისტრის სიმბოლოებისაგან
შედგენილი სტრიქონი სიგრძით 1–დან 32–მდე, ხოლო score არის მთელი რიცხვი
–1000..1000 დიაპაზონიდან.
გამოსატანი მონაცემები: გამოიტანეთ „ბერლოგინგის“ გამარჯვებულის სახელი.
#include<stdio.h>
#include<string.h>
typedef struct{
char name[36];
int score;
int subscore;
}player;
int main(void){
player pl[1024];
int i,j,k,n,now=0,flg,win=0;
int m=0;
struct{
char str[36];
int sc;
}input[1024];
scanf("%d%*c",&n);
for(i=0;i<n;i++){
scanf("%s %d%*c",input[i].str,&input[i].sc);
for(j=0,flg=0;j<now;j++){
if(!strcmp(input[i].str,pl[j].name)){
115
flg=1;
pl[j].score+=input[i].sc;
}
}
if(flg==1) continue;
strcpy(pl[now].name,input[i].str);
pl[now].score=input[i].sc;
pl[now].subscore=0;
now++;
}
for(i=0;i<now;i++)
if(m<pl[i].score) m=pl[i].score;
for(i=0;i<n;i++){
for(j=0;j<now;j++){
if(!strcmp(input[i].str,pl[j].name)){
pl[j].subscore+=input[i].sc;
break;
}
}
if(pl[j].subscore>=m && pl[j].score>=m){
puts(pl[j].name);
break;
}
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
struct vote_f {
int a;
int b;
int cownum;
} votes[50000];
comparea (struct vote_f *a, struct vote_f *b) { return b->a - a->a; }
compareb (struct vote_f *a, struct vote_f *b) { return b->b - a->b; }
main() {
int n, k, i;
117
გამოთვალეთ, რა მაქსიმალური რაოდენობის კლიენტის მომსახურება შეუძლია ვალერის
და გამოიტანეთ ამ კლიენტების ნომრები.
შესატანი მონაცემები: პირველ სტრიქონში მოცემულია ორი მთელი რიცხვი: n და d
(1≤n≤105, 1≤d≤109) – კლიენტების რაოდენობა და ფოტოაპარატის მეხსიერების მოცულობა.
მეორე სტრიქონში მოცემულია ორი მთელი რიცხვი: a და b (1≤a≤b≤104) — შესაბამისად
დაბალი და მაღალი ხარისხის სურათის ზომა. მომდევნო სტრიქონიდან თითოეულში
აღწერილია შეკვეთები. i–ურ სტრიქონში მოცემულია ორი მთელი რიცხვი: xi და yi
(0≤xi,yi≤105) – i–ური კლიენტის მიერ შეკვეთილი დაბალი და მაღალი ხარისხის სურათების
რაოდენობა.
გამოსატანი მონაცემები: პირველ სტრიქონში სტრიქონში ამოცანის პასუხი – რა
მაქსიმალური რაოდენობის კლიენტის მომსახურება შეუძლია ვალერის. მეორე სტრიქონში
გამოიტანეთ ამ კლიენტების ნომრები. ყველა ნომერი განსხვავებული უნდა იყოს. თუ პასუხი
რამდენიმეა – გამოიტანეთ ნებისმიერი.
ანალიზი. ცხადია, რომ ვალერი უფრო მეტ კლიენტს მოემსახურება, თუკი ამოარჩევს
ჯამურად ნაკლები მეხსიერების მომთხოვნ შეკვეთებს. ე.ი. ჩვენ უნდა დავთვალოთ თითოეული
კლიენტის სურათებისათვის საჭირო ჯამური მეხსიერება, დავალაგოთ ეს მონაცემი
ზრდადობით და თანმიმდევრობით შევასრულოთ შეკვეთები ვიდრე მეხსიერება გვეყოფა.
ერთადერთი პრობლემა აქ არის ის, რომ დალაგებისას დაიკარგება კლიენტთა თავდაპირველი
ნომრები. ეს რომ არ მოხდეს, გამოვიყენოთ pair სტრუქტურა. first ველში შევინახოთ
კლიენტის სურათებისათვის საჭირო მეხსიერების სიდიდე (რის მიხედვითაც შემდეგ უნდა
დავალაგოთ), ხოლო second ველში დავიმახსოვროთ კლიენტის ნომრები, რომელთაც
გამოვიტანთ პასუხად.
#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
int a,s,f,g,h,j,k,l,i,n,i1;
pair <int,int>d[100002];
main(){
cin>>n>>k;
cin>>g>>h;
for(i=0;i<n;i++){
cin>>j>>l;
d[i].first=j*g+h*l;
d[i].second=i+1;}
sort(d,d+n);
for(i=0;i<n;i++){
k=k-d[i].first;
if(k<0) {cout<<i<<endl;break;}}
118
if(i==n) {cout<<i<<endl;}
for(i1=0;i1<i;i1++){
cout<<d[i1].second<<" ";}
}
#include<stdio.h> #include<iostream>
#include<algorithm> #include<algorithm>
using namespace std; using namespace std;
typedef struct area{
int n,S,i;
int d;
pair<int,int> a[1005];
int f;
}saz; int main()
saz z[100005]; {cin>>S>>n;
bool mycompare(area v1, area for(i=1;i<=n;i++)
v2) { cin>>a[i].first>>a[i].second;
return v1.d < v2.d;
} sort(a+1,a+n+1);
int a,s,n,i,g,h,j,k,l; for(i=1;i<=n;i++){
119
if(S<=a[i].first)
main(){ {cout<<"NO"<<endl;return 0;}
scanf("%d",&n); S+=a[i].second;}
if(n==1) {printf("0");return 0;} cout<<"YES"<<endl;
}
for(i=0;i<n;i++){
scanf("%d%d",&z[i].d,&z[i].f);
}
sort(z,z+n,mycompare);a=z[0].f;
for(i=1;i<n;i++){
if(a>z[i].f) k++; else a=z[i].f;
}
printf("%d",k);}
120
მიმთითებელი
#include <iostream>
#include <string>
using namespace std;
int main(int){
int n;
char *name[]={"Sheldon", "Leonard", "Penny","Rajesh","Howard"};
cin>>n;
n--;
while(n>=5){
n-=5;
n/=2;
}
cout << s[n];
return 0;
}
121
კომბინირებული ამოცანები
•მოცემული ორობითი რიცხვი შევავსოთ ნულებით მარცხნიდან ისე, რომ ციფრების 000 0
001 1
საერთო რაოდენობა 3–ის ჯერადი გახდეს; 010 2
•თანმიმდევრულად დავაჯგუფოთ ორობითი 3–წევრიან ჯგუფებად. 011 3
•ორობითი ჩანაწერის თითოეული ჯგუფი შევცვალოთ შევცვალოთ რვაობითი 100 4
101 5
რიცხვით მარჯვნივ მოცემული ცხრილის შესაბამისად.
110 6
111 7
დაწერეთ პროგრამა, რომელიც გარდაქმნის რიცხვის ორობით კოდს რვაობითად.
შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია რიცხვის ორობითი ჩანაწერი. მასში
ციფრების რაოდენობა 100–ზე ნაკლებია და პირველი ციფრი 1–ის ტოლია.
გამოსატანი მონაცემები: მოცემული რიცხვის რვაობითი ჩანაწერი.
#include <iostream>
#include <string>
int main() {
string s;
cin >> s;
while( s != "" ) {
int x = 0;
if( s[0] == '1' ) x += 4;
if( s[1] == '1' ) x += 2;
if( s[2] == '1' ) x += 1;
printf( "%d", x );
s = s.substr( 3 );
}
printf( "\n" );
return 0;
}
122
ამოცანა 128. Profits - სარგებელი [Neal Wu, 2007]
USACO 2011 წლის იანვრის შეჯიბრი, “ვერცხლის” დივიზიონი
ძროხებმა დაიწყეს ახალი ბიზნესი. ფერმერ ჯონს უნდა ნახოს რამდენად კარგად
აკეთებენ ისინი საქმეს. ბიზნესი დაწყებულია N (1 <=N <= 100,000) დღის წინ და
ყოველ i-ურ დღეს ძროხებს ჩაწერილი აქვთ თავიანთი სარგებელი P_i (-1,000 <= P_i
<= 1,000).
ჯონს უნდა იპოვოს უდიდესი საერთო სარგებელი, რომელიც მიიღეს ძროხებმა
ნებისმიერ უწყვეტ პერიოდში. (გაითვალისწინეთ რომ ეს უწყვეტი პერიოდი შეიძლება
იყოს 1 დღიდან დაწყებული ნებისმიერი N დღემდე). დაეხმარეთ ჯონს და დაწერეთ
პროგრამა, რომელიც იპოვის უდიდესი სარგებლის მქონე უწყვეტი პერიოდის სარგებელს.
ამოცანის სახელი: profits
შეტანის ფორმატი:
სტრიქონი 1: ერთი მთელი: N
სტრიქონები 2..N+1: სტრიქონი i+1 შეიცავს ერთ მთელს: P_i
შეტანის ნიმუში (ფაილი profits.in):
7
-3
4
9
-2
-5
8
-3
გამოტანის ფორმატი:
სტრიქონი 1: ერთი მთელი - მაქსიმალური სარგებელი, რომელიღც უწყვეტი
პერიოდისათვის.
გამოტანის ნიმუში (ფაილი profits.out):
14
გამოტანის განმარტება:
მაქსიმალური სარგებელი გამოდის პერიოდისათვის მე-2 დღიდან ვიდრე მე-6-მდე (4, 9,
-2, -5, 8) => 14.
123
შემოვიღოთ მეორე მასივი სადაც ჯამებს გენერაციას მოვახდენთ და ამოცანის პასუხი სწორედ ამ
მასივის მაქსიმუმი იქნება. ვნახოთ ამ მასივის შევსება შეტანის ნიმუშისათვის:
საწყისი მასივი -3 4 9 -2 -5 8 -3
ჯამების მასივი -3 4 13 11 6 14 11
და ჩვენს მიერ მოდიფიცირებული შემთხვევისათვის
საწყისი მასივი -3 4 9 -4 -5 8 -17 -2 5 7
ჯამების მასივი -3 4 13 9 4 12 -5 -2 5 12
ჯამების მასივის მაქსიმუმი პირველ შემთხვევაში 14-ია და მეორე შემთხვევაში - 13.
#include<stdio.h>
#include<stdlib.h>
using namespace std;
int a,s,d[100000],f,g,h,j,i,o,p,m,k;
main(){
freopen("profits.in","r",stdin);
freopen("profits.out","w",stdout);
scanf("%d",&g);
for(s=0;s<g;s++){
scanf("%d",&d[s]);
}
for(j=1;j<g;j++) {
if (d[j-1]>0) d[j]=d[j]+d[j-1]; }
h=d[0];
for(j=1;j<g;j++)
if (h<d[j]) h=d[j];
printf("%d\n",h);
}
124
თვლის სისტემები. თვლის ორობითი სისტემა. კავშირი კომპიუტერის მეხსიერებაში ინფორმაციის
შენახვასა და ორობითი სისტემას შორის. ბიტი. ბაიტი.
თვლის სისტემა ეწოდება რიცხვთა ჩაწერის სიმბოლურ მეთოდს, რომელიც განსაზღვრავს
რიცხვთა წარმოდგენის წესებს. ადამიანს უძველესი დროიდან უწევდა სხვადასხვა საგნების
დათვლა. ამის გამო, სავარაუდოდ, თავდაპირველად თვლის უნარული სისტემა შეიქმნა, სადაც
რიცხვები აღინიშნებოდნენ შესაბამისი რაოდენობის ხაზებით.
ცხადია, რომ თვლის ასეთი სისტემა ფრიად მოუხერხებელია დიდი რიცხვების ჩასაწერად და
მათზე თუნდაც შეკრება-გამოკლების ოპერაციათა ჩასატარებლად, ამიტომ დროთა განმავლობაში
შეიქმნა სხვადასხვა სახის თვლის სისტემები, რომლებიც საბოლოო ჯამში, ორ ჯგუფად შეგვიძლია
დავყოთ: პოზიციური და არაპოზიციური.
თვლის არაპოზიციურ სისტემებში ციფრის წონა დამოკიდებული არაა მის პოზიციაზე.
თვლის ასეთი სისტემის ნიმუშია რომაული სისტემა. რომაულ სისტემაში ციფრებად გამოიყენება
შემდეგი სიმბოლოები: I(1), V(5), X(10), L(50), C(100), D(500), M(1000). რიცხვის მნიშვნელობა
განისაზღვრება როგორც მასში შემავალი ციფრების ჯამი ან სხვაობა. თუ სიდიდით ნაკლები
ციფრი დგას მეტი ციფრის მარცხნივ, მაშინ ის აკლდება, ხოლო თუ მარჯვნივ დგას - მაშინ ემატება.
მაგალითად, რიცხვი ოცდათერთმეტი რომაულად ასე ჩაიწერება - XXXI. ციფრ X-ს სამივე
პოზიციაში ერთი და იმავე მნიშვნელობა აქვს: ათი, ხოლო მარჯვნივ მდგომი ერთიანი ემატება
ათიანების ჯამს. რომ ყოფილიყო IXXX, მაშინ გვექნებოდა 29.
თვლის პოზიციურ სისტემებში ყოველი ციფრის წონა განისაზღვრება იმის მიხედვით, თუ რა
პოზიცია უჭირავს მას ციფრთა მიმდევრობაში. ნებისმიერი პოზიციური სისტემის მთავარი
მახასიათებელია ფუძე. თვლის პოზიციური სისტემის ფუძე წარმოადგენს განსხვავებულ
სიმბოლოთა (ნიშანთა) რაოდენობას, რომელიც გამოიყენება რიცხვების გამოსასახავად ამ
სისტემაში. ფუძედ შესაძლოა ავიღოთ ნებისმიერი ნატურალური რიცხვი - ორი, სამი, შვიდი, ათი,
თექვსმეტი და ა.შ. ცხადია, რომ პოზიციური სისტემების სიმრავლე უსასრულოა. შემდგომში
საუბარი მხოლოდ თვლის პოზიციურ სისტემებზე გვექნება.
რიცხვის ჩანაწერში მოცემულ ცალკეულ პოზიციას თანრიგს უწოდებენ, ხოლო პოზიციის
ნომერს - თანრიგის ნომერს. თანრიგების რაოდენობა ემთხვევა რიცხვის ჩანაწერის სიგრძეს.
ერთ-ერთი მთავარი მოთხოვნა თვლის სისტემებისადმი არის ნებისმიერი რიცხვის
უნიკალური გზით წარმოდგენა, თუმცა ეს ყოველთვის არ ხერხდება. განვიხილოთ თუნდაც
საყოველთაოდ მიღებული ათობითი სისტემა. იგი ნებისმიერ მთელ რიცხვს უნიკალური
(ერთადერთი) გზით წარმოგვიდგენს, მაგრამ როცა საქმე რაციონალურ ან ნამდვილ რიცხვებთან
გვაქვს, ეს უნიკალურობა ირღვევა. მაგალითად, თუ ავიღებთ არაპერიოდულ 111/1000=0.111-ს და
პერიოდული 1/9=0.111-ის ჩანაწერს მძიმის შემდეგ მესამე ნიშნამდე, ისინი ერთნაირად იქნებიან
წარმოდგენილი. ადგილი აქვს საპირისპირო სიტუაციასაც: ათწილადები 3.45 და 3.4500 ტოლად
ითვლება, თუმცა ისინი სხვადასხვა სახით არიან წარმოდგენილნი.
თვლის სისტემებს შორის ყველაზე გავრცელებულია ათობითი სისტემა, რომელშიც
გამოიყენება ათი ციფრი: 0, 1, 2, 3, 4, 5, 6, 7, 8 და 9. ყველაზე მარჯვენა ციფრი აღნიშნავს ერთეულთა
თანრიგს, მარჯვნიდან მეორე - ათეულთა თანრიგს, მარჯვნიდან მესამე - ასეულთა თანრიგს და ა.
შ. მაგ.: 746=7*100+4*10+6.
ელექტრონულ გამომთვლელ მანქანებში ფართოდ გამოიყენება ორობითი სისტემა ეს
განპირობებულია პროცესორისა და მეხსიერების ორგანიზაციის თავისებურებებით. თანამედროვე
კომპიუტერებში ეს მოწყობილობები დამზადებულია მკაცრად მოწესრიგებული კრისტალური
მესრის მქონე ნივთიერებებისაგან (ან შენადნობებისაგან) და შეიცავენ ერთმანეთისაგან
იზოლირებულ მილიარდობით უბანს. თითოეულ უბანში შესაძლებელია ელექტრული მუხტის
მოთავსება ან პირიქით, მუხტისაგან გათავისუფლება (მუხტის სიდიდეს არსებითი მნიშვნელობა
არ ენიჭება). ანუ ყოველ უბანს გააჩნია ორი მდგომარეობა, რომლებიც პირობითად შეიძლება 0-ით
125
და 1-ით აღვნიშნოთ. ამგვარად, კრისტალური მესრის უბნები შეიძლება წარმოვიდგინოთ, როგორც
0-ებისა და 1-ების მიმდევრობა. თითოეული უბანი წარმოადგენს ინფორმაციის შესანახ
მინიმალურ ერთეულს და მას ბიტს უწოდებენ. 8 ბიტის ერთობლიობას უწოდებენ ბაიტს.
1 ტერაბაიტი=1024 გიგაბაიტი; 1 გიგაბაიტი=1024 მეგაბაიტი; 1 მეგაბაიტი=1024 კილობაიტი;
1 კილობაიტი=1024 ბაიტი;1 ბაიტი= 8 ბიტი
სწორედ იმის გამო, რომ ბიტს შეუძლია მხოლოდ ორნაირი მნიშვნელობა მიიღოს,
ელექტრონული გამომთვლელი მანქანები დაფუძნებულია თვლის ორობით სისტემაზე. ორობით
სისტემაშიც ნებისმიერი ნატურალური რიცხვი უნიკალური გზით გამოსახება. აქ შეგვიძლია
პარალელი გავავლოთ იმ ფაქტთან, რომ ნებისმიერი ნატურალური რიცხვი შეიძლება
წარმოდგენილ იქნას, როგორც 2-ის ხარისხების ჯამი. რიცხვის ჩანაწერში ყველაზე მარჯვენა
თანრიგი მიუთითებს შესაბამის ჯამში 1-იანის არსებობას (ეს იგივე, რაც 2-ის ნულოვანი ხარისხი),
მარჯვნიდან მეორე თანრიგი - 2-ის არსებობას, მარჯვნიდან მესამე - 4-ის არსებობას და ა.შ.
მაგალითად:
4310=1010112=1*25+0*24+1*23+0*22+1*21+1*20=32+8+2+1
ინდექსებად მითითებულია თვლის სისტემის ფუძე, ანუ 43 ათობით ჩანაწერში, იგივეა რაც
101011 ორობით ჩანაწერში.
თვლის რვაობით სისტემაში რვა ციფრია: 0, 1, 2, 3, 4, 5, 6 და 7. ხოლო თექვსმეტობით
სისტემაში 16 სიმბოლო გამოიყენება: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F. ცხადია, თვლის
პოზიციურ სისტემებს შორის რაიმე პრინციპული განსხვავება არ არსებობს გარდა იმისა, რომ რაც
უფრო დიდია თვლის სისტემის ფუძე, მით უფრო კომპაქტურია რიცხვის ჩანაწერი. თუმცა
ადამიანი იმდენადაა მიჩვეული ათობით სისტემას, რომ მისი სხვა სისტემით ჩანაცვლება
ყოველდღიურ ცხოვრებაში წარმოუდგენელია. ინფორმატიკაში ფართოდ გამოიყენება ორობითი,
რვაობითი და თექვსმეტობითი სისტემები. უფრო დიდი ფუძის მქონე სისტემებს მასში
გამოყენებული სიმბოლოების სიმრავლის გამო პრაქტიკულად არ გამოიყენება.
ქვემოთ მოცემულ ცხრილში ნაჩვენებია, თუ როგორ ჩაიწერება რიცხვები 1-დან 17-მდე
თვლის ზოგიერთ სისტემაში. მარცხენა ნულები შეგვიძლია უგულვებელვყოთ.
126
1. რიცხვების შეკრება-გამოკლება თვლის მოცემულ სისტემაში; რიცხვების გადაყვანა თვლის ერთი
სისტემიდან მეორეში.
არითმეტიკული ოპერაციები ორობითი, თექვსმეტობითი თუ სხვა ფუძის მქონე თვლის
სისტემებში ხორციელდება იმავე წესებით, როგორც ეს ათობით სისტემაში ხდება. განვიხილოთ ეს
ოპერაციები ცალ-ცალკე.
მოვიყვანოთ შეკრების ცხრილი ორობითი სისტემისათვის. ცხრილში რუხი ფერით
მონიშნული რიცხვების გადაკვეთაზე ჩაწერილია ამ ორი რიცხვის ჯამი.
0 1
0 0 1
1 1 10
თანრიგები 7 6 5 4 3 2 1
პირველი შესაკრები 1 0 0 1 1
მეორე შესაკრები 1 0 0 0 1 1 1
ჯამი 1 0 1 1 0 1 0
თუკი ჯამის რომელიმე თანრიგში ჯამი 2-ის ტოლია. იმ თანრიგში ვწერთ 0-ს, ხოლო
მეზობელ მარცხენა თანრიგს ვუმატებთ 1-ს. ცხადია, რომ 100112+10001112=10110102 ტოლობა
ათობით სისტემაშიც ჭეშმარიტია: 1910+7110=9010.
მოვიყვანოთ შეკრების ცხრილი თექვსმეტობითი სისტემისათვის
0 1 2 3 4 5 6 7 8 9 А В С D E F 10
0 0 1 2 3 4 5 6 7 8 9 A B C D E F 10
1 1 2 3 4 5 6 7 8 9 A B C D E F 10 11
2 2 3 4 5 6 7 8 9 A B C D E F 10 11 12
3 3 4 5 6 7 8 9 A B C D E F 10 11 12 13
4 4 5 6 7 8 9 A B C D E F 10 11 12 13 14
5 5 6 7 8 9 A B C D E F 10 11 12 13 14 15
6 6 7 8 9 A B C D E F 10 11 12 13 14 15 16
7 7 8 9 A B C D E F 10 11 12 13 14 15 16 17
8 8 9 A B C D E F 10 11 12 13 14 15 16 17 18
9 9 A B C D E F 10 11 12 13 14 15 16 17 18 19
A A B C D E F 10 11 12 13 14 15 16 17 18 19 1A
B B C D E F 10 11 12 13 14 15 16 17 18 19 1A 1B
C C D E F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C
D D E F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D
E E F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E
F F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
10 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20
127
მაგალითისათვის შევკრიბოთ ორი თექვსმეტობითი რიცხვი 9D6F და 5A0:
თანრიგები 4 3 2 1
პირველი შესაკრები 9 D 6 F
მეორე შესაკრები 5 A 0
ჯამი A 3 0 F
თანრიგები 7 6 5 4 3 2 1 6 5 4 3 2 1
საკლები 1 0 1 1 0 0 1 C 4 0 A D 7
მაკლები 1 1 0 1 1 1 6 C 3 B 4
სხვაობა 1 0 0 0 1 0 B D 4 7 2 3
0 1 2 3 4 5 6 7 8 9 A B C D E F
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 0 1 2 3 4 5 6 7 8 9 A B C D E F
2 0 2 4 6 8 A C E 10 12 14 16 18 1A 1C 1E
3 0 3 6 9 C F 12 15 18 1B 1E 21 24 27 2A 2D
4 0 4 8 C 10 14 18 1C 20 24 28 2C 30 34 38 3C
5 0 5 A F 14 19 1E 23 28 2D 32 37 3C 41 46 4B
6 0 6 C 12 18 1E 24 2A 30 36 3C 42 48 4E 54 5A
7 0 7 E 15 1C 23 2A 31 38 3F 46 4D 54 5B 62 69
8 0 8 10 18 20 28 30 38 40 48 50 58 60 68 70 78
9 0 9 12 1B 24 2D 36 3F 48 51 5A 63 6C 75 7E 87
A 0 A 14 1E 28 32 3C 46 50 5A 64 6E 78 82 8C 96
B 0 B 16 21 2C 37 42 4D 58 63 6E 79 84 8F 9A 100
C 0 C 18 24 30 3C 48 54 60 6C 78 84 90 9C 108 114
D 0 D 1A 27 34 41 4E 5B 68 75 82 8F 9C 109 116 123
E 0 E 1C 2A 38 46 54 62 70 7E 8C 9A 108 116 124 132
F 0 F 1E 2D 3C 4B 5A 69 78 87 96 100 114 123 132 141
128
ამ ცხრილის გამოყენებით გადავამრავლოთ თექვსმეტობითი 4C6 და A5F:
4 C 6
* D 5 F
4 7 9 A
1 7 D E
3 E 0 E
3 F D 3 7 A
მოვიყვანოთ გაყოფის მაგალითები 2–ითი, 8–ითი და 16–ითი სისტემებისათვის:
1001100100110002 : 1010112=1110010002;
462308 : 538=7108;
4C9816 : 2B16=1C816.
129
130
3. დაპროგრამების ენა C-ს შესავალი. C-ს ძირითადი ცნებები (ანბანი, ცვლადი, მუდმივა,
იდენტიფიკატორი, რეზერვირებული სიტყვები, კომენტარი).
დაპროგრამების ენა C შეიქმნა 1972 წელს ამერიკული კორპორაციის AT&T Bell Laboratory-ის
თანამშრომლის დენის რიჩის მიერ. C იღებს თავის საწყისებს ორი ენიდან: B და BCPL (აქედანაა
განპირობებული მისი სახელიც, როგორც B-ს გაუმჯობესება). დღეისათვის პრაქტიკულად ყველა
ძირითადი ოპერაციული სისტემა დაწერილია C-ზე და/ან C++-ზე. C-ს უწოდებენ საშუალო დონის
დაპროგრამების ენას, რადგანაც მასში განხორციელებულია მაღალი დონის ალგორითმული ენების
ყველა საუკეთესო თვისება და კომპიუტერის აპარატურასთან უშუალო წვდომის შესაძლებლობა,
მაგალითად, თითოეულ ბიტზე წვდომა (რაც, ჩვეულებრივ, შესაძლებელია ასემბლერზე
დაპროგრამებისას). ენის პირველი აღწერა – დენის რიჩის და ბრაიან კერნიგანის წიგნი “The ‘C’
Programming Language” – გამოვიდა 1978 წელს, და დიდი ხნის მანძილზე ეს იყო ენის ერთადერთი
აღწერა (სტანდარტი). C-ს უპირატესობათაგან უნდა აღინიშნოს, რომ მისი შესრულება
შესაძლებელია სხვადასხვა არქიტექტურის მანქანებზე, სხვადასხვა ოპერაციულ სისტემებში.
რადგანაც C-ს აქვს მაღალი დონის ალგორითმული ენის ყველა დამახასიათებელი კომპონენტი,
იგი მალევე გახდა პოპულარული აგრეთვე როგორც გამოყენებითი პროგრამირების ენა. C-ს
გამოყენებამ სხვადასხვა ტიპის კომპიუტერებზე (იტყვიან – სხვადასხვა პლატფორმაზე) გამოიწვია
ენის ვერსიების გაჩენა, რაც ხშირად უშლიდა პროგრამების თავსებადობას. ამიტომაც, 1983 წელს
ამერიკის სტანდარტების ნაციონალურმა კომიტეტმა ინფორმაციის დამუშავებისა და
კომპიუტერების დარგში დააწესა ტექნიკური კომისია, რომელსაც დაევალა ცალსახა და მანქანურ-
დამოუკიდებელი C-ენის განსაზღვრა, ანუ სტანდარტის შემუშავება. სტანდარტი საბოლოოდ
დამტკიცებულია 1989 წელს, ხოლო 1988 წელს გამოვიდა კერნიგანის და რიჩის წიგნის მეორე
გამოცემა, რომელშიც აღწერილია C-ს ბოლო ვერსია. ეს ვერსია ცნობილია როგორც ANSI C და
ფართოდ გამოიყენება მსოფლიოში.
80-ანი წლების დასაწყისში იგივე Bell Laboratory-ში ბერნ სტრაუსტრუპის მიერ იყო
შემოთავაზებული C-ენის გაფართოება, რომელსაც თავიდან ეწოდებოდა “C კლასებით” და
რომელიც სინამდვილეში იყო ახალი ობიექტზე ორიენტირებული ენა. მას მოგვიანებით დაერქვა
C++. C++-ში შესაძლებელია პროგრამირება C-ს სტილშიც, ობიექტზე ორიენტირებულ სტილშიც და
ორივე სტილში ერთდროულად. მე-20 საუკუნის 90-იანი წლების დასაწყისიდან C++ გახდა
მსოფლიოში ერთ-ერთი ყველაზე აღიარებული ენა.
C-ს ანბანი
1. ინგლისური ენის ასოები (მთავრული და პატარა ასოები განსხვავდებიან)
და ქვედა ხაზის სიმბოლო
ABCDEFGHIJKLMNOPQRSTUVWXYZ
abcdefghijklmnopqrstuvwxyz _
2. არაბული ციფრები
0123456789
3. სპეციალური სიმბოლოები და არითმეტიკული ოპერაციების აღმნიშვნელი სიმბოლოები
, . ; : ? ' ! | / \ ~ * + – ) ( } { < > [ ] # % & ^ " და სხვა
4. გამყოფი და მმართველი სიმბოლოები
ესენია: ჰარი, ტაბულაციის სიმბოლოები, ახალ სტრიქონზე გადასვლის სიმბოლო და სხვა
5. ამას გარდა გამოიყენება ე.წ. მმართველი მიმდევრობები, ანუ სიმბოლოების სპეციალური
კომბინაციები. ზოგიერთი მათგანია: \b (ერთი პოზიციით დაბრუნება); \t (ჰორიზონტალური
ტაბულაცია); \n (ახალ სტრიქონზე გადასვლა); \0 (ნულოვანი სიმბოლო); \r (კურსორის გადატანა
სტრიქონის დასაწყისში) და სხვა.
131
მუდმივა. ცვლადი. იდენტიფიკატორი.
პროგრამული მონაცემს (ან შეიძლება ითქვას, ობიექტს), რომელსაც მნიშვნელობა ენიჭება
პროგრამის შესრულების დაწყებამდე და შემდეგ, პროგრამის შესრულების დროს, ეს მნიშვნელობა
აღარ ეცვლება მუდმივას, ანუ კონსტანტას (constant) უწოდებენ. თუკი თავდაპირველად
მნიშვნელობა ეცვლება, მაშინ მონაცემს ცვლადი (variable) ეწოდება. ყოველ მუდმივას ან ცვლადს
უნდა ჰქონდეს სახელი, ანუ იდენტიფიკატორი, რომელიც შედგება ასოების, ციფრებისა და ქვედა
ხაზის სიმბოლოებისაგან. ამასთან, იდენტიფიკატორი უნდა იწყებოდეს ასოთი ან ქვედა ხაზის
სიმბოლოთი და არ უნდა იწყებოდეს ციფრით. ლათინური ანბანის მთავრული და პატარა ასოები
C-ში განსხვავდებიან (ზოგიერთი პროგრამული ენისაგან განსხვავებით). ამიტომ
იდენტიფიკატორები ab, Ab, aB და AB – 4 სხვადასხვა იდენტიფიკატორია. სწორი
იდენტიფიკატორების მაგალითებია: dkFG327, new_height, MaXiMuM, _raodenoba, ხოლო zurab.kar,
7ab, new height, – იდენტიფიკატორის არასწორი ჩაწერაა. იდენტიფიკატორის სიგრძეზე C++-ში
შეზღუდვა არ არის.
კომენტარი C-ში
C-ზე დაწერილ პროგრამაში შეიძლება გამოვიყენოთ კომენტარი, რომელიც გააიოლებს
პროგრამის აღქმას არა მარტო სხვა პროგრამისტისათვის, არამედ თავად ავტორისათვისაც.
პროგრამის კომპილაციისას კომენტარს ყურადღება არ ექცევა, ამიტომ ის არანაირ გავლენას არ
ახდენს პროგრამის მუშაობაზე, თუკი, რა თქმა უნდა, წესების დაცვითაა მითითებული. კომენტარი
შესაძლოა ორნაირად გაკეთდეს: დაკომენტარდეს ტექსტი სტრიქონის რომელიმე პოზიციიდან
ამავე სტრიქონის ბოლომდე ან დაკომენტარდეს ტექსტის გარკვეული ბლოკი, რომელიც შეიძლება
მიმდევრობით განლაგებულ რამდენიმე სტრიქონსაც შეიცავდეს. პირველ შემთხვევაში
გამოიყენება ორი დახრილი ხაზი: //, ხოლო მეორე შემთხვევაში სიმბოლოები /* და */ . სადაც /*
კომბინაცია წარმოადგენს კომენტარის დასაწყისს, ხოლო */ – კომენტარის დასასრულს. კომენტარის
შიგნით კომენტარის აღმნიშნელი სიმბოლოების /* და */ გამოყენება აკრძალულია. მაგალითად,
სწორად ჩაწერილი კომენტარებია:
// S kvadratis fartobia. ან
/* S carmoadgens
kvadratis fartobs.*/
შემდეგი კომენტარები შეიცავენ შეცდომას:
/* P S kvadratis fartobia. ან
/* S carmoadgens */ kvadratis /* fartobs. */
132
4. მონაცემთა საბაზო ტიპები. ტიპის მოდიფიკატორები. ცვლადების გამოცხადება, ინიციალიზება.
0 0 0 0 0 0 0 0 0 0 0 0 10 0 1
მე- ……. . . მე- 0-მე- მე- 1-
15 4 ოვანი
3 2 ლი
ბიტი
მე-15 (უფროსი) ბიტი – ნიშანთვისების ბიტია, ანუ იგი აჩვენებს რიცხვის ნიშანს: თუ მე-15 ბიტში
წერია 0 – რიცხვი დადებითია, თუ კი მე-15 ბიტი უდრის 1-ს – რიცხვი უარყოფითია. ამიტომ
რიცხვის სიდიდის ჩასაწერად გამოიყენება 15 ბიტი (0-ვანიდან მე-14-მდე). როდესაც
გამოცხადებულია უარყოფითი მთელი რიცხვი, კომპილატორი ახდენს ე.წ. დამატებითი კოდის
გენერირებას, რომელიც ამ უარყოფითი რიცხვის კოდია. მაგალითად, უარყოფითი რიცხვი -3
ჩაიწერება კომპიუტერის მეხსიერებაში როგორც
1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1
მე-15 ……. . . მე-4 მე-3 მე-2 1- 0-ოვანი
ლი ბიტი
რიცხვი -3-ის წარმოდგენა მიიღება შემდეგნაირად:
+3-ს წარმოდგენაში 0-ები იცვლება 1-ბით და, პირიქით, 1-ები 0-ებით (რის შედეგადაც
მიიღება შებრუნებული კოდი); შემდეგ კი უმცროს ბიტს ემატება 1. მიღებული ორობითი რიცხვი
(დამატებითი კოდი) არის უარყოფითი რიცხვი -3-ის წარმოდგენა კომპიუტერის მეხსიერებაში.
როდესაც რიცხვის აღწერაში გამოიყენება მოდიფიკატორი unsigned, ამ რიცხვის უფროსი
ბიტი უკვე არ განიხილება როგორც ნიშნის მაჩვენებელი. იგი განიხილება როგორც რიცხვის
სიდიდის ჩასაწერად გამოყოფილი კიდევ ერთი ბიტი (ანუ რიცხვის სიდიდის ჩასაწერად
გამოიყენება 16-ვე ბიტი), და მაშინ ამ რიცხვის ცვლილების დიაპაზონი იწყება 0-დან და იზრდება 2-
ჯერ.
ტიპები float და double აღწერენ ნამდვილ რიცხვებს, ამბობენ – რიცხვებს “მცოცავი
წერტილით”. ეს ნიშნავს, რომ ხდება რიცხვის მასშტაბირება წერტილის გადაცოცებით მარცხნივ ან
მარჯვნივ. ამ დროს რიცხვის მნიშვნელობა რომ არ შეიცვალოს, მას ამრავლებენ 10-ის შესაბამის
ხარისხზე (E=10). მაგალითად,
123.456789=1.23456789 * E+2= 12345678.9 * E-5. აქ +2 და -5 არის 10-ის ხარისხები.
float იკავებს მეხსიერებაში 4 ბაიტს, double კი – 8 ბაიტს. ამასთან double ტიპის ცვლადს
უწოდებენ “მცოცავი წერტილით ორმაგი სიზუსტის” ცვლადს, რადგანაც მისი წილადი ნაწილის
შესანახად გამოიყოფა 52 ბიტი, ხოლო float ტიპის ცვლადის წილად ნაწილს ეთმობა 23 ბიტი.
134
double ტიპთან შეიძლება გამოვიყენოთ მოდიფიკატორი long. long double მეხსიერებაში
იკავებს 10 ბაიტს.
შემდეგ ცხრილში მოყვანილია ყველა შესაძლო ტიპი მოდიფიკატორების სხვადასხვა
კომბინაციებით
ზომა ბაიტებში
ტიპი მნიშვნელობათა დიაპაზონი
(ბიტებში)
char 1 (8) -128 -დან +127-მდე
unsigned char 1 (8) 0 -დან +255-მდე
signed char 1 (8) -128 -დან +127-მდე
int 2 (16) -32768 -დან +32767-მდე
unsigned int 2 (16) 0 -დან +65535-მდე
signed int 2 (16) -32768 -დან +32767-მდე
short int 2 (16) -32768 -დან +32767-მდე
unsigned short int 2 (16) 0 -დან +65535-მდე
signed short int 2 (16) -32768 -დან +32767-მდე
long int 4 (32) -2147483648-დან +2147483647-მდე
signed long int 4 (32) -2147483648-დან +2147483647-მდე
unsigned long int 4 (32) 0-დან +4294967295-მდე
long long int 8 (64) -(263-1)-დან (263-1)-მდე
unsigned long long int 8 (64) 0-დან (264-1)-მდე
float 4 (32) 3.4E-38-დან 3.4E+38-მდე
double 8 (64) 1.7 E-308-დან 1.7 E+308-მდე
long double 10 (80) 3.4E-4932-დან 3.4E+4932-მდე
135