ზაზა გამეზარდაშვილი პროგრამირების...

135
1 ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია და ამოცანები

Upload: others

Post on 23-Aug-2020

87 views

Category:

Documents


3 download

TRANSCRIPT

Page 1: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

1

ზაზა გამეზარდაშვილი

პროგრამირების საფუძვლები

თეორია და ამოცანები

Page 2: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

2

არითმეტიკული და შეტანა-გამოტანის ოპერაციები

C++–ში, ისევე როგორც პროგრამირების სხვა ენებში, პროგრამა წარმოადგენს ბრძანებების

ერთობლიობას, რომელიც თანმიმდევრობით სრულდება. თანმიმდევრობის შეცვლა

(მაგალითად, ზოგიერთი ბრძანების გამოტოვება, ან უკვე შესრულებულ ბრძანებაზე

დაბრუნება) სპეციალური ბრძანებებით ხორციელდება. ბრძანებები იწერება წინასწარ

განსაზღვრული სიტყვების საშუალებით, რომლებსაც რეზერვირებულ სიტყვებს უწოდებენ.

პროგრამირების თითოეულ ენას რეზერვირებულ სიტყვათა საკუთარი სიმრავლე აქვს, თუმცა

ასეთ სიტყვათა დიდი ნაწილი და ამ სიტყვებით შექმნილი კონსტრუქციები პროგრამირების

ბევრ ენაში საერთოა. პროგრამირების ენებს, განსხვავებით სალაპარაკო ენებისაგან, გააჩნია

ძალზე მკაცრი სინტაქსი და მისი დაუცველობის შემთხვევაში კომპილატორი (ბრძანებების

შემსრულებელი) ვერ გაიგებს ჩვენ მიერ ჩაწერილ ბრძანებას და ვერ შეასრულებს მას.

ყველაზე ხშირად პროგრამირების დროს მინიჭების ოპერაცია ხორციელდება. C++–ში ამ

ოპერაციისათვის გამოიყენება ტოლობის ნიშანი („=“), მაგრამ, განსხვავებით მათემატიკისაგან,

a=7 და 7=a ჩანაწერები არ არის ერთნაირი შინაარსის შემცველი. პროგრამირებაში

გამოსახულების მხოლოდ მარცხენა მხარეს ენიჭება მარჯვნივ მდგომი გამოსახულების

მნიშვნელობა და არა პირიქით. შესაბამისად, მარცხენა მხარეში მხოლოდ ერთი ცვლადი

შეიძლება იმყოფებოდეს, ხოლო მარჯვენაში შესაძლებელია რთული გამოსახულების ჩაწერაც.

მაგალითად: B=n+(t1*t1-20)-jami/2.

მოყვანილ გამოსახულებაში B, n, t1 და jami ცვლადთა სახელებია. ცვლადთა

სახელებს პროგრამისტი ირჩევს, თუმცა არსებობს გარკვეული შეზღუდვებიც (არ უნდა

იწყებოდეს ციფრით, არ უნდა ემთხვეოდეს რეზერვირებულ სიტყვას, არ უნდა შეიცავდეს

სასვენ ნიშნებს და ა.შ.). მარჯვენა მხარეში მდგომ ცვლადებს ამ გამოსახულების შესრულებამდე

აუცილებლად უნდა ჰქონდეთ მინიჭებული რიცხვითი მნიშვნელობები, რადგან ოპერაციები

C++–ში მხოლოდ რეალურ რიცხვებზე სრულდება. მინიჭების ოპერატორს აქვს კიდევ ერთი

„არამათემატიკური“ თვისება. მაგალითად: X=8;

X=X+5;

ოპერაციების შემდეგ X–ის მნიშვნელობა 13 იქნება. მეორე სტრიქონში მოცემული ტოლობის

მარცხენა და მარჯვენა მხარეებში გამოყენებული X–ები შინაარსობრივად განსხვავდება.

მარჯვენა მხარეში X–ს აქვს ის მნიშვნელობა, რომელიც მიმდინარე სტრიქონამდე ჰქონდა

მინიჭებული, ხოლო მარცხენა მხარეში ჩაწერილ X–ს მნიშვნელობა მიენიჭება მიმდინარე

სტრიქონის შესრულების შემდეგ.

მინიჭების ოპერაციის არსში უკეთ გასარკვევად განვიხილოთ მაგალითი, რომელიც

ხშირად გვხვდება პრაქტიკაში. ვთქვათ, საჭიროა ორი ცვლადისათვის მნიშვნელობების გაცვლა,

ანუ თუ a=4 და b=9, ჩვენი მოქმედებების შედეგად a უნდა გახდეს 9 და b უნდა გახდეს 4

(ცხადია, რომ მოქმედებები უნდა შესრულდეს არა კონკრეტული რიცხვებისათვის, არამედ

ზოგადად). უშუალოდ a=b; b=a; ბრძანებები სასურველ შედეგამდე ვერ მიგვიყვანს, რადგან

პირველი ბრძანების შემდეგ ორივე ცვლადის მნიშვნელობა b-ის ტოლი გახდება და ამავე

მნიშვნელობებს შეინარჩუნებენ ცვლადები მეორე ბრძანების შემდეგაც. დამატებითი (ვთქვათ, c)

ცვლადის გამოყენებით ამოცანის ამოხსნა მარტივია. დავუშვათ, პროგრამის შესრულების რაღაც

მომენტში a=4, b=9 და c=0. ქვემოთ, ცხრილში ნაჩვენებია, თუ რა მნიშვნელობას მიიღებენ

ცვლადები თითოეული სტრიქონის შესრულების შემდეგ:

პროგრამის

კოდი

ცვლადების მნიშვნელობები შესაბამის ბიჯზე

a b c

c=a; 4 9 4

a=b; 9 9 4

b=c; 9 4 4

Page 3: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

3

იგივე ამოცანა შეიძლება გადაიჭრას დამატებითი ცვლადის გამოყენების გარეშეც. მაშინ

ანალოგიურ ცხრილს ექნება სახე:

პროგრამის

კოდი

ცვლადების მნიშვნელობები შესაბამის ბიჯზე

a b

a=a-b; –5 9

b=a+b; –5 4

a=b-a; 9 4

ქვემოთ მოყვანილია არითმეტიკული ოპერაციების აღნიშვნათა ცხრილი:

+ შეკრება – გამოკლება * გამრავლება / გაყოფა (როგორც მთელი, ასევე მოძრავმძიმიანი) % ნაშთის გამოთვლა ++ ინკრემენტი (1–ით გაზრდა) –– დეკრემენტი (1–ით შემცირება)

შეტანა–გამოტანის ოპერაციები C++–ში რამდენიმე განსხვავებული გზით ხორციელდება.

ბრძანებათა ნაწილი (მაგალითად, scanf და printf) C–ის თავდაპირველ ვერსიაშიც

არსებობდა, ხოლო უფრო პოპულარული cin და cout კი C++–ის შექმნის მერე დაემატა. ჩვენ,

შეძლებისდაგვარად, ყველა ბრძანებას გამოვიყენებთ, რადგან ყველას აქვს თავისი

უპირატესობა. მაგალითად, დიდი რაოდენობით რიცხვითი მონაცემების კითხვის ან

გამოტანისას scanf და printf გაცილებით სწრაფია, ვიდრე cin და cout.

ამოცანა 1. ორნიშნა რიცხვის ციფრთა ჯამი

მოცემულია ორნიშნა მთელი რიცხვი N (10 <= N <= 99). დაწერეთ პროგრამა, რომელიც

გამოიტანს მის ციფრთა ჯამს.

შესატანი მონაცემები: მოცემულია ერთი მთელი ორნიშნა რიცხვი N.

გამოსატანი მონაცემები: ერთი მთელი რიცხვი – N-ის ციფრთა ჯამი.

შესატანი მონაცემები გამოსატანი მონაცემები

61 7

20 2

ანალიზი. ჯერ გავერკვიოთ მთელი გაყოფის არსში. C++-ში ბრძანებების შესრულებამდე

აუცილებელია განისაზღვროს პროგრამაში გამოყენებული თითოეული ცვლადის ტიპი.

რიცხვითი ცვლადების ორი უმთავრესი ტიპია – მთელი და მოძრავმძიმიანი (ანუ ათწილადი).

თუ გაყოფის შედეგი მთელი ტიპის ცვლადს ენიჭება, მაშინ სრულდება ე.წ. მთელი გაყოფა (მაგ.

19/5=3) და ათწილადი ნაწილი იკარგება, ხოლო თუ გაყოფის შედეგი მოძრავმძიმიანი ტიპის

ცვლადს ენიჭება, მაშინ გამოითვლება ათწილადი ნაწილიც (მაგ. 19/5=3.8). ჩვენს ამოცანაში

მოქმედებები მხოლოდ მთელი ტიპის ცვლადებზე ხდება, ამიტომ მხოლოდ მთელი გაყოფის

ოპერაციები სრულდება. ორნიშნა რიცხვის ერთეულების თანრიგში მდგომი ციფრი შეიძლება

დავადგინოთ ამ რიცხვის 10-ზე გაყოფის ნაშთით, ხოლო ათეულების თანრიგში მდგომი ციფრი

– ამ რიცხვის 10-ზე მთელი გაყოფით. ნაშთის გამოთვლის ოპერაცია ხდება “%” სიმბოლოთი,

ხოლო მთელი გაყოფა “/” სიმბოლოთი. აქედან გამომდინარე გამოსახულება k=N%10+N/10;

გამოითვლის N რიცხვის ერთეულების და ათეულების თანრიგებში მდგომი ციფრების ჯამს.

Page 4: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

4

მიაქციეთ ყურადღება გამოსახულების ბოლოში დასმულ წერტილ-მძიმეს. C++-ში

აუცილებელია ნებისმიერი ბრძანება წერტილ-მძიმეთი მთავრდებოდეს.

ჯამი შეიძლება გამოვთვალოთ უშუალოდ გამოტანის ოპერატორში ან შეგვიძლია

გამოტანამდე სხვა ცვლადს მივანიჭოთ მისი მნიშვნელობა.

ახლა ვნახოთ როგორ გამოიყურება პროგრამა სრული სახით.

#include<iostream>

using namespace std;

int N;

main(){

cin>>N;

cout<<N/10+N%10;

}

#include<stdio.h>

int N,k;

main(){

scanf("%d",&N);

k=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 ცვლადის მნიშვნელობა.

ამოცანა 2. საშუალო არითმეტიკული

გიორგის დაავალეს გამოთვალოს ორი მთელი A და B (0 <= A, B <= 30000) რიცხვის

საშუალო არითმეტიკული. დაწერეთ პროგრამა, რომელიც შეასრულებს ამ დავალებას.

შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია ორი მთელი რიცხვი A და B.

გამოსატანი მონაცემები: ერთი რიცხვი – A და B-ს საშუალო არითმეტიკული.

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი

35 81 58.0

14 29 22.5

Page 5: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

5

ანალიზი. ამ ამოცანაში გამოსატანი მონაცემები მთელი ტიპის არ არის, ამიტომ უნდა

გამოვიყენოთ რომელიმე მოძრავძიმიანი ტიპი float ან double, თუმცა სწორი პასუხის

მისაღებად მხოლოდ აღწერა საკმარისი არ არის. რადგან (a+b)/2 გამოსახულებაში ორივე

ცვლადი მთელი ტიპისაა, შესრულდება მთელი გაყოფის ოპერაცია და რიგ შემთხვევაში

პროგრამა არასწორ პასუხს გამოიტანს. მაგ. ამოცანის მეორე ტესტში 22.5-ის ნაცვლად მივიღებთ

22.0-ს. ასეთი უზუსტობის თავიდან ასაცილებლად საჭიროა გამოსათვლელი გამოსახულების

წინ მივუთითოთ ჩვენთვის სასურველი ტიპი.

ორი მთელი რიცხვის საშუალო არითმეტიკული მძიმის შემდეგ მხოლოდ ერთ რიცხვს

შეიძლება შეიცავდეს. გარკვეული მოქმედებებია საჭირო იმისათვის, თუ გვინდა, რომ

ათწილადში ზედმეტი 0-ები არ დაიბეჭდოს. მძიმის შემდეგ ციფრის რაოდენობა cout-სათვის

რეგულირდება setprecision ბრძანებით (სჭირდება ბიბლიოთეკა <iomanip.h>). იგივე

საკითხი printf-ის გამოყენებისას გამოსატანი რიცხვის სპეციფიკაციაში მიეთითება (“%.1f).

#include<stdio.h>

int a,b;

float c;

main(){

scanf("%d%d",&a,&b);

c=(float) (a+b)/2;

printf("%.1f",c);

}

#include<iostream>

#include <iomanip.h>

using namespace std;

int a,b;

double x;

main(){

cin>>a>>b;

x=(double) (a+b)/2;

cout<< setprecision(1)<<x<<endl;

}

ამოცანა 3. სიგრძის ერთეულები

დაწერეთ პროგრამა, რომელიც ფუტებსა და დიუმებში მოცემულ სიგრძეს გადაიყვანს

სანტიმეტრებში. 1 ფუტი=30,48სმ, 1 დიუმი=2,54სმ.

შესატანი მონაცემები: ორი მთელი რიცხვი - შესაბამისად ფუტებისა და დიუმების

რაოდენობა. ორივე რიცხვი მოთავსებულია დიაპაზონში 1..100.

გამოსატანი მონაცემები: ერთი ნამდვილი რიცხვი - იგივე სიგრძე სანტიმეტრებში.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი

2 3 68.58

ანალიზი. წავიკითხოთ შესატანი მონაცემები ორ ცვლადში, შესაბამის რიცხვებზე

გადავამრავლოთ და შევკრიბოთ.

#include <iostream>

using namespace std;

int a,b;

main(){

cin>>a>>b;

cout<<a*30.48+b*2.54;

}

ამოცანა 4. სამნიშნა რიცხვის შებრუნებული ჩანაწერი

მოცემულია სამნიშნა მთელი რიცხვი N (100 <= N <= 999), რომელიც არ მთავრდება 0-ით.

დაწერეთ პროგრამა, რომელიც გამოიტანს ამ რიცხვის შებრუნებულ ჩანაწერს.

შესატანი მონაცემები: ერთი მთელი სამნიშნა რიცხვი N .

გამოსატანი მონაცემები: ერთი მთელი რიცხვი – N-ის შებრუნებული ჩანაწერი.

Page 6: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

6

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი

845 548

601 106

ანალიზი. წინა ამოცანის მსგავსად, რიცხვის ერთეულების თანრიგში მდგომი ციფრი

შეიძლება დავადგინოთ ამ რიცხვის 10-ზე გაყოფის ნაშთით, ასეულების თანრიგში მდგომი

ციფრი – ამ რიცხვის 100-ზე მთელი გაყოფით, ხოლო ათეულების თანრიგში მდგომი ციფრი

შეიძლება ორნაირად მივიღოთ: ა) რიცხვის 100-ზე გაყოფის ნაშთი მთელად გავყოთ 10-ზე; ბ)

რიცხვის 10-ზე მთელი გაყოფის შედეგის 10-ზე გაყოფის ნაშთი ვიპოვოთ. ციფრების მიღების

შემდეგ შეგვიძლია ისინი უბრალოდ დავბეჭდოთ შებრუნებული თანმიმდევრობით, ან

მივიღოთ შებრუნებული რიცხვი და შემდეგ დავბეჭდოთ. ქვემოთ ნაჩვენებია ორივე ვარიანტი.

#include<stdio.h>

int n,a,b,c;

main(){

scanf("%d",&n);

a=n%10; b=(n/10)%10; c=n/100;

printf("%d%d%d",a,b,c);

}

#include<iostream>

using namespace std;

int n,a,b,c;

main(){

cin>>n;

a=n%10; b=(n%100)/10; c=n/100;

n=a*100+b*10+c;

cout<<n<<endl;

}

ამოცანა 5. დროის ფორმატი

მოცემულია მთელი N (0 < N < 30000) წამი. დაწერეთ პროგრამა, რომელიც დროის იგივე

მონაკვეთს გამოიტანს ფორმატით “საათი:წუთი:წამი”.

შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია ერთი მთელი რიცხვი N.

გამოსატანი მონაცემები: დროის იგივე შუალედი ამოცანაში მითითებული ფორმატით.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი

3676 1:1:16

37 0:0:37

60 0:1:0

ანალიზი. მოცემული რიცხვისაგან საათების რაოდენობის გასაგებად საჭიროა ის მთელი

გაყოფით გავყოთ 3600-ზე (წამთა რაოდენობა საათში) და ცალ-ცალკე ცვლადებში

დავიმახსოვროთ როგორც მთელი გაყოფის შედეგი, ასევე ნაშთი. ანალოგიურად, წუთების

რაოდენობის დასადგენად საჭიროა უკვე მიღებული ნაშთი გავყოთ 60-ზე. ამ მთელი გაყოფის

შედეგი იქნება წუთების რაოდენობა, ხოლო ნაშთი – წამების რაოდენობა.

გამოტანისას საჭიროა ორწერტილების დასმა რიცხვებს შორის. cout-ში ამის გაკეთება

მარტივი აღსაქმელია. ბრჭყალებში მოთავსებული ნებისმიერი ტექსტი უცვლელად იბეჭდება.

იმავე მიზნისათვის printf-იც ბრჭყალებს იყენებს, ოღონდ ორწერტილები სპეციფიკაციებს

შორის თავსდება და არა ცვლადებს შორის. ამ შემთხვევაშიც ბრჭყალებში მოთავსებული ტესტი

უცვლელად იბეჭდება სპეციფიკაციების გარდა. #include<stdio.h>

int n,clo,minu, sec;

main(){

scanf("%d",&n);

clo=n/3600;

minu=(n%3600)/60;

sec=n%60;

printf("%d:%d:%d",clo,minu,sec);

}

#include<iostream>

using namespace std;

int n,clo,minu, sec;

main(){

cin>>n;

clo=n/3600;minu=(n%3600)/60;

sec=n%60;

cout<<clo<<":"<<minu<<":"<<sec;

}

Page 7: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

7

ამოცანა 6. დროის შუალედი

მეტეოროლოგმა ჩაიწერა მზის ამოსვლის და ჩასვლის დროები წამების სიზუსტით.

თითოეული ჩანაწერი მოცემულია ჰარით გაყოფილი სამი მთელი A , B და C რიცხვებით,

რომლებიც შესაბამისად აღნიშნავენ საათს, წუთსა და წამს (1 ≤ A ≤ 23; 0 ≤ B, C ≤ 59). დაწერეთ

პროგრამა, რომელიც გამოითვლის რამდენი წამი გავიდა დროის ამ ორ მომენტს შორის.

შესატანი მონაცემები: ორი სტრიქონიდან თითოეულში მოცემულია სამ-სამი მთელი

რიცხვი – შესაბამისად მზის ამოსვლის და ჩასვლის დროები.

გამოსატანი მონაცემები: ერთი მთელი რიცხვი – განსხვავება დროის ორ მომენტს შორის

წამებში.

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი

7 14 35

17 25 14

36639

ანალიზი. პასუხი მხოლოდ წამების ნაცვლად საათებსა და წუთებშიც რომ იყოს

გამოსატანი, მაინც აჯობებს, დროის ორივე მომენტი ჯერ წამებში გადავიყვანოთ და შემდეგ

გამოვთვალოთ სხვაობა.

#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. დომინოს დაწყობა

(http://codeforces.com/problemset/problem/50/A)

მოცემულია მართკუთხა უჯრედოვანი დაფა, რომელიც შედგება M×N უჯრედისაგან.

მასთან ერთად მოცემულია 2×1 ზომის დომინოს ქვები შეუზღუდავი რაოდენობით. საჭიროა

დაფის დაფარვა დომინოს ქვებით ისე, რომ შესრულდეს შემდეგი პირობები:

1. დომინოს ყოველი ქვა მთლიანად ფარავს დაფის ორ უჯრას;

2. ქვების არცერთი წყვილი არ ფარავს ერთმანეთს (თუნდაც ნაწილობრივ);

3. ყოველი ქვა მთლიანად დევს დაფის შიგნით. კიდესთან შეხება დასაშვებია.

დომინოს ქვების შეტრიალება შესაძლებელია. გამოთვალეთ ქვების მაქსიმალური

რაოდენობა, რომელიც დაფაზე დაეტევა.

შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია ჰარით გაყოფილი ორი მთელი

რიცხვი M და N (1 ≤ M ≤ N ≤ 16).

გამოსატანი მონაცემები: ერთი მთელი რიცხვი – დომინოს ქვების მაქსიმალური

რაოდენობა, რომელიც დაფაზე დაეტევა.

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი

2 4 4

3 3 4

Page 8: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

8

ანალიზი. რადგან ქვების შეტრიალება ნებადართულია და თითოეული ქვა ზუსტად ორ

უჯრას ფარავს, ცხადია, რომ ნებისმიერი ლუწი სიგრძის სტრიქონის ან სვეტის დაფარვა

სრულადაა შესაძლებელი. ამ ფაქტის გამო დაფა მთლიანად დაიფარება ქვებით, თუკი მისი

ერთ–ერთი გვერდი მაინც არის ლუწი სიგრძის. თუ ორივე გვერდი კენტი სიგრძისაა, მაშინ

შეუვსებელი დარჩება მხოლოდ ერთი უჯრა. #include<iostream>

using namespace std;

int m,n;

main(){

cin>>m>>n;

cout<<m*n/2;

}

ამოცანა 8. თეატრალური მოედანი

(http://codeforces.com/problemset/problem/1/A)

თეატრალური მოედანი ბერლანდიის დედაქალაქში წარმოადგენს n×m მეტრი ზომის

მართკუთხედს. ქალაქის იუბილესთან დაკავშირებით გადაწყდა, რომ მოედანზე დააგონ

გრანიტის ფილები. თითოეული ფილის ზომაა a×a მეტრი.

რა მინიმალური რაოდენობის ფილაა საჭირო მოედნის დასაფარავად? დაშვებულია

თეატრალურ მოედანზე უფრო დიდი ფართობის დაფარვა, ოღონდ მოედანი უსათუოდ

მთლიანად უნდა დაიფაროს. გრანიტის ფილების დანაწევრება არ შეიძლება. ფილათა გვერდები

მოედნის გვერდების პარალელური უნდა იყოს.

შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია ჰარით გაყოფილი სამი მთელი

რიცხვი n, m და a (1 ≤ n,m,a ≤ 109).

გამოსატანი მონაცემები: ერთი მთელი რიცხვი – ფილების საჭირო რაოდენობა.

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი

6 6 4 4

ანალიზი. თუკი m უნაშთოდ იყოფა a–ზე, მაშინ სიგრძეში დასალაგებელი ფილების

რაოდენობა იქნება m/a, წინააღმდეგ შემთხვევაში დაგვჭირდება ერთი ფილით მეტი, ანუ m/a+1

ფილა. ეს ორი შემთხვევა შეიძლება გავაერთიანოთ გამოსახულებაში: (m+a–1)/a, რომელიც m/a–ს

ტოლია, თუკი m უნაშთოდ იყოფა a–ზე, ხოლო ყველა სხვა შემთხვევაში m/a+1 ტოლი იქნება.

ანალოგიურად შეგვიძლია გამოთვალოთ სიგანეში დასალაგებელი ფილების რაოდენობა, ხოლო

სულ საჭირო იქნება ამ ორი რიცხვის ნამრავლი.

#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

ექვსის ჯერადები არიან.

გამოსატანი მონაცემები: ერთი მთელი რიცხვი – ქათმების მიერ დადებული კვერცხების

რაოდენობა.

Page 9: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

9

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი

6 9 36

ანალიზი. დადებული კვერცხების რაოდენობა იმდენჯერ მეტი იქნება 1.5–ზე,

რამდენჯერაც მეტი იქნებიან n და m 1.5–ზე ცალ–ცალკე, ანუ პასუხი იქნება

1.5*(n/1.5)*(m/1.5)=n*m/1.5.

#include <iostream>

using namespace std;

int n,m;

main(){

cin>>n>>m;

cout<<n*m/1.5;

}

ამოცანა 10. ათწილადი ნაწილი

მოცემულია ჰარით გაყოფილი ორი მთელი რიცხვი A და B (1≤A, B≤999). დაწერეთ

პროგრამა, რომელიც გამოიტანს A-ს B-ზე განაყოფის ათწილადი ნაწილის პირველ 3 ციფრს.

შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია ორი მთელი რიცხვი A და B .

გამოსატანი მონაცემები: ერთი მთელი რიცხვი – N-ის ციფრთა ჯამი.

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი

15 13 0.153

22 5 0.400

ანალიზი. პირველ რიგში გამოსათვლელია a ცვლადის b-ზე ჩვეულებრივი განაყოფი.

ამის შემდეგ საჭიროა მოვაშოროთ მას მთელი ნაწილი. ეს კი მიიღწევა განაყოფისათვის იმავე

რიცხვების მთელი გაყოფის შედეგად მიღებული რიცხვის გამოკლებით. კიდევ ერთხელ

აღვნიშნოთ C++-ის თავისებურება მთელ რიცხვებთან დამოკიდებულებაში. კერძოდ, თუ

გაყოფის ოპერაცია მთელ რიცხვებზე სრულდება, მაშინ შედეგიც ფორმირდება როგორც მთელი

გაყოფის ოპერაციის დროს. ამიტომ საჭიროა ტიპის განსაზღვრა ოპერაციის შედეგისათვის.

პირველ კოდში ეს ხორციელდება (float) ინსტრუქციით c=(float) a/b; სტრიქონში,

ხოლო მეორეში – (double) ინსტრუქციით. მძიმის შემდეგ 3 ციფრის გამოტანა რეგულირდება

შესაბამისად printf და setprecision ბრძანებებით.

#include<stdio.h>

#include<stdlib.h>

int n,a,b;

float c;

main(){

scanf("%d%d",&a,&b);

c=(float) a/b -(int) a/b;

printf("%.3f",c);

}

#include<iostream>

#include<stdlib.h>

#include <iomanip.h>

using namespace std;

int a,b;

double x;

main(){

cin>>a>>b;

x=(double) a/b-(int) a/b;

cout<<setprecision(3)<<x;

}

Page 10: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

10

ამოცანა 11. საახალწლო სანთლები

(http://codeforces.com/problemset/problem/379/A)

ვასოს რომანტიკა უყვარს, ამიტომ გადაწყვიტა საახალწლოდ ოთახი სანთლებით

გაანათოს. მას აქვს a ცალი სანთელი. როცა ვასო ანთებს ახალ სანთელს, ის იწვის ზუსტად 1

საათი და შემდეგ ქრება. b ცალი ჩამქრალი სანთლიდან ვასო აკეთებს ერთ სანთელს, რომელიც

შეუძლია ახალივით გამოიყენოს.

ახლა ვასოს აინტერესებს, რამდენ საათის განმავლობაში ეყოფა მას თავისი სანთლები,

თუკი ოპტიმალურად იმოქმედებს. დაწერეთ პროგრამა, რომელიც გამოთვლის ამ რიცხვს.

შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია ორი მთელი რიცხვი

a და b (1≤a≤1000; 2≤b≤1000).

გამოსატანი მონაცემები: ერთი მთელი რიცხვი – საათების რაოდენობა, რომლის

განმავლობაშიც ვასოს შეუძლია ოთახის განათება.

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი 4 2 7

6 3 8

განმარტება. პირველ მაგალითში ვასო აანთებს სანთლებს 4 საათის განმავლობაში და 4

დამწვარი სანთლიდან გააკეთებს ორ ახალს და როცა ეს ორიც დაიწვება, მათი ნარჩენიდან

გააკეთებს კიდევ 1 ახალს, რაც ჯამში 7 საათის განმავლობაში გაანათებს.

ანალიზი. პასუხი მოთავსებული იქნება 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;

}

ამოცანა 12. პარალელეპიპედი http://codeforces.com/problemset/problem/224/A

მოცემულია მართკუთხა პარალელეპიპედი, რომლის წიბოთა სიგრძეები მთელი

რიცხვებით გამოისახება. ცნობილია მისი საერთო წიბოების მქონე სამი წახნაგის ფართობები.

იპოვეთ პარალელეპიპედის თორმეტივე წიბოს ჯამი.

შესატანი მონაცემები: ერთადერთ სტრიქონში სამი დადებითი მთელი რიცხვი - საერთო

წიბოების მქონე სამი წახნაგის ფართობები. არცერთი ფართობი არ აღემატება 10000-ს.

გამოსატანი მონაცემები: ერთადერთი რიცხვი – პარალელეპიპედის ყველა წიბოს ჯამი.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 1 1 1 12

4 6 6 28

Page 11: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

11

ანალიზი. ვთქვათ, პარალელეპიპედის წიბოებია 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 15 19 4 3 2

ანალიზი. ფორმულიდან S=(R1+R2)/2 გამოვთვალოთ R2. მივიღებთ R2= 2*S –R1. #include <iostream>

int r1, s;

main(){

cin>>r1>>s;

cout<<2*s-r1;

}

Page 12: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

12

შედარების ოპერატორი

შედარების ოპერატორი გამოიყენება პროგრამაში განშტოებათა ორგანიზებისათვის (ამის

გამო მას ხშირად განშტოების ოპერატორს უწოდებენ). მისი ფორმატია:

if (გამოსახულება) ოპერატორი1; [else ოპერატორი2;]

if ოპერატორის შესრულება იწყება გამოსახულების მნიშვნელობის გამოთვლიდან,

რომელსაც ორი შესაძლო პასუხი აქვს – ჭეშმარიტი (ანუ განსხვავებულია 0–საგან) და მცდარი

(ანუ 0). შემდეგ შესრულება გრძელდება ამგვარი სქემით:

▪ თუ გამოსახულება ჭეშმარიტია, სრულდება ოპერატორი1.

▪ თუ გამოსახულება მცდარია, სრულდება ოპერატორი2.

▪ თუ გამოსახულება მცდარია და ოპერატორი2 არაა მოცემული, მაშინ სრულდება

ოპერატორი , რომელიც უშუალოდ if–ის შემდეგაა.

▪ ერთდროულად ოპერატორი1–ის და ოპერატორი2–ის შესრულება შეუძლებელია.

დასაშვებია ერთმანეთში ჩადგმული if ოპერატორების გამოყენება. იგი შესაძლოა

ჩადგმული იქნას სხვა if–ის (ან სხვა else–ს) შიგნით. ასეთ დროს რეკომენდირებულია

ფიგურული ფრჩხილების გამოყენება, რომელთა არარსებობის შემთხვევაში კომპილიატორი

თავად აწყვილებს else–ებს უახლოეს if–ებთან, რომელსაც else არ აქვს.

ოპერატორი შედეგი

== ტოლია

!= არ უდრის

> მეტია

< ნაკლებია

>= მეტია ან ტოლი

<= ნაკლებია ან ტოლი

გამოსახულებაში დაუშვებელია ორმაგი უტოლობების გამოყენება (მაგ. 5<s<=276). ასეთი

პირობების ჩაწერა ხორციელდება ე.წ. ლოგიკური ოპერატორებით, რომელთა ჩამონათვალი

მოცემულია ცხრილში:

ოპერაცია სინტაქსი მაგალითი

უარყოფა (NOT) ! if (a!=7) k=9

ლოგიკური და (AND) && if (a>10)&&(a<100)

ლოგიკური ან (OR) || if (a>=b)||a(>=c)

უარყოფა ჭეშმარიტ გამოსახულებას აქცევს მცდარად, ხოლო მცდარს – ჭეშმარიტად.

„ლოგიკური და“ ჭეშმარიტია მხოლოდ მაშინ, როცა მასში შემავალი ორივე პირობა ჭეშმარიტია,

ხოლო „ლოგიკური ან“ ჭეშმარიტია მაშინ, თუ მასში შემავალი ერთი მაინც პირობა არის

ჭეშმარიტი.

განშტოებათა ორგანიზების სხვა საშუალებაა ოპერატორი switch, რომელიც გამოიყენება

მრავლობითი ამორჩევის დროს. ოპერატორი switch (ზოგჯერ მას გადამრთველსაც

უწოდებენ) გამოიყენება ისეთ შემთხვევებში როცა განშტოება უნდა განხორციელდეს

გამოსახულების მნიშვნელობის მიხედვით. პროგრამის მიერ გამოითვლება გამოსახულების

მნიშვნელობა და ის სიაში ჩამოთვლილ ჭდეთა მნიშვნელობებს, რომლებიც შესაძლოა იყვნენ

მთელი ან სიმბოლური ტიპის. switch ოპერატორის ზოგადი ფორმა ასეთია:

Page 13: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

13

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–ში მეორის ჩადგმა.

ამოცანა 14. აკვარიუმი

ბულგარეთის ეროვნული ოლიმპიადა (2010 წელი, საწყისი ეტაპი, 4-5 კლასი)

აკვარიუმში ოქროს თევზების ნორმალურად გამრავლებისათვის აუცილებელია, რომ

ერთ თევზზე 3 ლიტრი წყალი მოდიოდეს.

დაწერეთ პროგრამა, რომელიც V ლიტრი ტევადობის მქონე აკვარიუმისა და N ცალი

ოქროს თევზისათვის დაადგენს, რამდენი თევზის გადაყვანაა საჭირო სხვა ადგილას, რომ

მოცემულ აკვარიუმში თევზებს გამრავლების ნორმალური პირობა შეექმნათ.

შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია ჰარით გაყოფილი ორი

მთელი რიცხვი V და N (1 ≤ V, N ≤ 1018 ).

გამოსატანი მონაცემები: თუ აკვარიუმიდან საჭიროა ოქროს თევზების ნაწილის სხვა

ადგილას გადაყვანა, პროგრამამ ერთ სტრიქონში გამოიტანოს ჰარით დაშორებული YES და

გადასაყვანი თევზების მინიმალური რაოდენობა, ხოლო თუ არცერთი თევზის გადაყვანა არაა

საჭირო, პროგრამამ გამოიტანის NO.

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი 12 5 YES 1 128 39 NO

ანალიზი. გავყოთ აკვარიუმის ტევადობა 3–ზე და გამოვთვალოთ იმ თევზების

რაოდენობა, რომელთათვისაც ეს ტევადობა საკმარისია. შემდეგ გამოვთვალოთ N–ისა და ამ

რიცხვის სხვაობა.

Page 14: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

14

#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";

}

ამოცანა 15. სიმღერა

ბულგარეთის ეროვნული ოლიმპიადა (2009 წელი, საწყისი ეტაპი, 4-5 კლასი)

როზენმა საკუთარი კომპიუტერის მყარი დისკი თამაშებით აავსო და ახლა მას

აინტერესებს, დაეტევა თუ არა მასზე მისი საყვარელი სიმღერა. სიმღერის ხანგრძლივობა n

წუთი და m წამია, თავისუფალი ადგილი მყარ დისკზე – k მეგაბაიტი, ხოლო სიმღერის 1 წამის

შესანახად მეხსიერებაში საჭიროა 16 კილობაიტი (1 მეგაბაიტი=1024 კილობაიტი).

დაწერეთ პროგრამა, რომელიც გამოიტანს YES , თუ დისკზე თავისუფალი ადგილი

საკმარისია. იმ შემთხვევაში, თუ სიმღერის ჩასაწერად მეხსიერება არ გვყოფნის, პროგრამამ

ცალ–ცალკე სტრიქონებში გამოიტანოს შეტყობინება NO და სიმღერის ჩასაწერად საჭირო

მეხსიერების რაოდენობა კილობაიტებში.

შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია სამი მთელი რიცხვი n, m და k

(1<= n, m, k <=1 000 000 000).

გამოსატანი მონაცემები: პროგრამამ პირველ სტრიქონში გამოიტანოს YES, თუ დისკზე

თავისუფალი ადგილი საკმარისია და NO – წინააღმდეგ შემთხვევაში. უარყოფითი პასუხის

შემთხვევაში მეორე სტრიქონში გამოიტანეთ სიმღერის ჩასაწერად საჭირო მეხსიერების

რაოდენობა კილობაიტებში.

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი 36 5 6 NO

28496 YES YES

ანალიზი. გადავიყვანოთ სიმღერის ზომა წუთებიდან და წამებიდან კილობაიტებში,

ხოლო თავისუფალი მეხსიერება – მეგაბაიტებიდან კილობაიტებში. გავითვალისწინოთ, რომ

შემომავალი რიცხვები მილიარდამდეა და ცვლადები აღვწეროთ long long ტიპში. გადაყვანის

შემდეგ მიღებული ორი სიდიდე შევადაროთ ერთმანეთს და გამოვიტანოთ შესაბამისი პასუხი.

#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;

}

Page 15: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

15

ამოცანა 16. გამრავლება

ბულგარეთის ეროვნული ოლიმპიადა (2010 წელი, საწყისი ეტაპი, 4-5 კლასი)

მოცემულია სამნიშნა რიცხვი. დაწერეთ პროგრამა, რომელიც დაადგენს იმ უდიდესი

რიცხვის მნიშვნელობას, რომელიც შესაძლოა მივიღოთ ამ რიცხვის ციფრებს შორის

გამრავლების ერთი ნიშნის ჩასმით.

შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია ერთი მთელი სამნიშნა რიცხვი.

გამოსატანი მონაცემები: ერთადერთ სტრიქონში გამოიტანეთ მაქსიმალური შესაძლო

პასუხი.

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი 358 280

553 265

ანალიზი. რადგან რიცხვი სამნიშნაა, გამრავლების ნიშნის ჩასასმელად სულ ორი

ვარიანტი არსებობს: ა) პირველ და მეორე ციფრებს შორის; ბ) მეორე და მესამე ციფრებს შორის.

გამოვთვალოთ ორივე შემთხვევის პასუხი და შევადაროთ ერთმანეთს.

#include<iostream>

using namespace std; int a,m1,n1,m2,n2,s,p;

main(){

cin >> a;

m1 = a/10; n1 = a%10; s = m1*n1;

m2 = a/100; n2 = a%100; p = m2*n2;

if (s > p) cout << s << endl;

else cout << p << endl;

}

ამოცანა 17. საზამთრო http://codeforces.com/problemset/problem/4/A

ზაფხულის ერთ ცხელ დღეს პეტრემ და ვასომ საზამთრო იყიდეს. აწონვის შემდეგ

აღმოჩნდა, რომ საზამთრო w კილოგრამია. ბავშვები აპირებენ მის გაყოფას ორ ნაწილად, მაგრამ

ეს არც ისე იოლი აღმოჩნდა – ორივე მათგანი ლუწი რიცხვების მოყვარულია და სურს, რომ მის

წილს ლუწი რიცხვით გამოსახული წონა ჰქონდეს. ამასთან, აუცილებელი არაა, რომ საზამთრო

თანაბრად გაიყოს. დაეხმარეთ ბავშვებს პრობლემის გადაწყვეტაში.

შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია ერთი მთელი რიცხვი w (1 ≤ w ≤

100), ბავშვების მიერ ნაყიდი საზამთროს წონა.

გამოსატანი მონაცემები: გამოიტანეთ YES, თუ საზამრთოს გაყოფა ხერხდება ორ ნაწილად

ისე, რომ ორივე ნაწილის წონა დადებითი ლუწი რიცხვებით იყოს გამოსახული. თუ ასეთი

გაყოფა შეუძლებელია, გამოიტანეთ NO.

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი

8 YES

ანალიზი. კენტი რიცხვების გაყოფა ორ ლუწ ნაწილად შეუძლებელია. ლუწი რიცხვებიდან

კი 2–ის გარდა ყველას გაყოფა შეიძლება აღნიშნული წესით. #include <iostream>

using namespace std;

int n;

main() {

cin>>n;

if (n%2==0 && n>2) cout<<"YES"; else cout<<“NO”;

Page 16: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

16

}

ამოცანა 18. სამკუთხედის აგება

დაწერეთ პროგრამა, რომელიც მოცემული სამი A, B და C (0 <= A, B, C <= 30000)

რიცხვებისათვის შეამოწმებს, შესაძლებელია თუ არა შესაბამისი სიგრძეების მონაკვეთებით

სამკუთხედის აგება. დადებითი პასუხის შემთხვევაში პროგრამამ გამოიტანოს – “YES”, თუკი

სამკუთხედი არ აიგება – “NO”.

შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია სამი მთელი A, B და C.

გამოსატანი მონაცემები: გამოიტანეთ YES, თუ სამკუთხედის აგება შესაძლებელია და

წინააღმდეგ შემთხვევაში გამოიტანეთ NO.

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი

12 19 14 YES

11 29 10 NO

ანალიზი. სამი მონაკვეთით სამკუთხედის აგება შესაძლებელია მხოლოდ მაშინ, თუკი

თითოეული მათგანის სიგრძე ნაკლებია დანარჩენი ორის სიგრძეების ჯამზე. #include <iostream>

int a,b,c;

main() {

cin>>a>>b>>c;

if ((a+b>c) && (a+c>b) && (b+c>a)) cout<<"YES"; else cout<<“NO”; }

ამოცანა 19. პოზიციათა რაოდენობა

http://codeforces.com/problemset/problem/124/A

პეტრე დგას n ადამიანისაგან შედგენილ რიგში, მაგრამ ზუსტად არ იცის - რომელ

ადდილას. მას შეუძლია თქვას, რომ მის წინ დგას არანაკლებ a ადამიანი, ხოლო მის შემდეგ -

არაუმეტეს b ადამიანი. გამოთვალეთ პოზიციათა რაოდენობა, რომელზეც შეიძლება პეტრე

იმყოფებოდეს.

შესატანი მონაცემები: ერთ სტრიქონში მოცემულია სამი მთელი რიცხვი - n, a და b

(0≤a,b<n≤100). გამოსატანი მონაცემები: ერთი მთელი რიცხვი - შესაძლებელი პოზიციების რაოდენობა.

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი 3 1 1 2

5 2 3 3

განმარტება. პირველ მაგალითში პეტრე შეიძლება იმყოფებოდეს 2 და 3 პოზიციებში (თუ

გადანომვრას 1-დან დავიწყებთ), ხოლო მეორეში - 2,3 და 5 პოზიციებში.

ანალიზი. თუ პეტრეს შემდეგ დგას არაუმეტეს b ადამიანი, მისი პოზიციების რაოდენობა

იქნება b+1. თუ მის წინ დგას a ადამიანი, მისი პოზიციების რაოდენობა იქნება n-a. ეს ორი

რიცხვი ერთმანეთთან გარკვეულ კავშირშია და ერთი მიმართულებით პოზიციების ზრდა

მეორე მიმართულებითაც გაზრდის პოზიციებს. ამის გამო პასუხად უმცირესი უნდა ავირჩიოთ. #include<iostream>

using namespace std;

int n,a,b;

int main(){

cin>>n>>a>>b;

b++;

if(b>n-a) cout<<n-a; else cout<<b;

}

Page 17: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

17

ამოცანა 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 რიცხვი, ზემოთ მითითებული

დიაპაზონების მიხედვით.

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი 127 byte

130 short

123456789101112131415161718192021222324 BigInteger

ანალიზი. ერთ-ერთი მთავარი პრობლემა ამოცანის ამოხსნისას მონაცემების სწორად

წაკითხვაა. ცხადია, რომ ასნიშნა რიცხვს ვერცერთ მთელი ტიპის ცვლადში ვერ წავიკითხავთ.

Char-სიმბოლოებად წაკითხვის შემთხვევაში გართულდება დიაპაზონების საზღვრების

დადგენა. ყველაზე მარტივი გამოსავალია მონაცემების წაკითხვა long double-ში, რომელიც

მართალია დიდ რიცხვებს გარკვეული ცდომილებით შეინახავს, მაგრამ ეს ცდომილება არანაირ

როლს არ ითამაშებს ცვლადის ტიპთა დიაპაზონებთან შედარებისას.

#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";

}

Page 18: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

18

ამოცანა 21. მეოთხე წერტილი

ხორვატიის ღია პირველობა ინფორმატიკაში (2007/08 წელი, შეჯიბრი 1)

მირკოს უნდა შეარჩიოს 4 წერტილი სიბრტყეზე ისე, რომ ისინი ჰქმნიდნენ მართკუთხედს,

რომლის გვერდები საკოორდინატო ღერძების პარალელურია. მან უკვე შეარჩია 3 წერტილი და

დარწმუნებულია, რომ შეცდომა არ დაუშვია. მეოთხე წერტილის შერჩევა კი გაუჭირდა.

დაეხმარეთ მირკოს და დაწერეთ პროგრამა, რომელიც იპოვის მეოთხე წერტილის

კოორდინატებს.

შესატანი მონაცემები: სამი სტრიქონიდან თითოეულში მოცემულია ორ-ორი მთელი

რიცხვი – შესაბამის წერტილის კოორდინატები სიბრტყეზე. თითოეული კოორდინატი

წარმოადგენს მთელ რიცხვს და მოთავსებულია დიაპაზონში 1-დან 1000-მდე.

გამოსატანი მონაცემები: ერთადერთ სტრიქონში გამოიტანეთ ორი მთელი რიცხვი –

მეოთხე წერტილის კოორდინატები.

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი 5 5

5 7

7 5

7 7

30 20

10 10

10 20

30 10

ანალიზი. ჯერ განვიხილოთ მხოლოდ x კოორდინატები. ცხადია, რომ ორი მათგანი

ერთმანეთს უნდა დაემთხვეს (სხვაგვარად, მათი შემაერთებელი მონაკვეთი OY ღერძის

პარალელური ვერ იქნება), ხოლო ჩვენს საძიებელ წერტილს ექნება მესამე (კენტად დარჩენილი)

წერტილის ტოლი x კოორდინატი. ანალოგიური მსჯელობით მივიღებთ y კოორდინატს.

#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;

}

ამოცანა 22. განტოლებები

ხორვატიის ღია პირველობა ინფორმატიკაში (2007/08 წელი, შეჯიბრი 5)

პატარა მირკომ საკუთარ ნოუთბუქში შეადგინა არითმეტიკული განტოლებები სამ-სამი

რიცხვიდან, რომლებშიც გამოიყენა ტოლობის ნიშანი და ერთ-ერთი ოპერაცია ოთხი

არითმეტიკული მოქმედებიდან – შეკრება, გამოკლება, გამრავლება და გაყოფა. საკმარისი იყო,

რომ მირკოს რამდენიმე წუთით დაეტოვებინა ნოუთბუქი უყურადღებოდ, რომ სლავკომ წაშალა

ყველა ოპერაციის და ტოლობის ნიშანი და მხოლოდ რიცხვები დატოვა. დაეხმარეთ მირკოს

განტოლებების აღდგენაში.

შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია ჰარით დაშორებული სამი

მთელი რიცხვი. თითოეული რიცხვი მოთავსებულია დიაპაზონში 1-დან 100-მდე.

გამოსატანი მონაცემები: ერთადერთ სტრიქონში გამოიტანეთ შემომავალი რიცხვებისაგან

შედგენილი ჭეშმარიტი ტოლობა. რიცხვების თანმიმდევრობა დაცული უნდა იყოს. შემომავალი

მონაცემები უზრუნველყოფენ პასუხის არსებობას. რამდენიმე პასუხის არსებობის შემთხვევაში

გამოიტანეთ ერთ-ერთი.

Page 19: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

19

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი 5 3 8 5+3=8

5 15 3 5=15/3

ანალიზი. ტოლობის ნიშანი ნებისმიერ განტოლებაში უნდა ფიგურირებდეს. ის შეიძლება

მოთავსებული იყოს პირველ და მეორე ან მეორე და მესამე რიცხვებს შორის. ამ ორი

შემთხვევიდან თითოეულისათვის განვიხილოთ ოთხივე არითმეტიკული ოპერაცია.

მაშასადამე, სულ განსახილველი იქნება 8 ვარიანტი. თითოეული შემთხვევისათვის ცალ-ცალკე

შედარების დაწერის შემთხვევაში არსებობს საშიშროება, რომ პროგრამამ ერთის ნაცვლად

რამდენიმე სწორი პასუხი გამოიტანოს (მაგ. 4-2=2 და 4/2=2 ), ამიტომ შედარების ოპერატორები

ერთმანეთში ჩავსვათ და თუ რომელიმე მათგანი დაკმაყოფილდა, დანარჩენები აღარ

შემოწმდება. #include <cstdio>

int a, b, c;

main( ) {

scanf( "%d%d%d", &a, &b, &c );

if( a == b+c ) printf( "%d=%d+%d\n", a, b, c );

else if( a == b-c ) printf( "%d=%d-%d\n", a, b, c );

else if( a == b*c ) printf( "%d=%d*%d\n", a, b, c );

else if( a == b/c ) printf( "%d=%d/%d\n", a, b, c );

else if( a+b == c ) printf( "%d+%d=%d\n", a, b, c );

else if( a-b == c ) printf( "%d-%d=%d\n", a, b, c );

else if( a*b == c ) printf( "%d*%d=%d\n", a, b, c );

else if( a/b == c ) printf( "%d/%d=%d\n", a, b, c );

}

ამოცანა 23. სამი კენგურუ

ხორვატიის ღია პირველობა ინფორმატიკაში (2008/09 წელი, შეჯიბრი 1)

სამი კენგურუ თამაშობს უდაბნოში. ისინი დგანან ერთ სწორ ხაზზე და სამივე მათგანის

კოორდინატები განსხვავებულია. ყოველ სვლაზე ერთ-ერთი განაპირა კენგურუ ხტება დანარჩენ

ორს შორის (აუცილებელი არაა ზუსტად შუაში ჩახტეს). არცერთ მომენტში ორი კენგურუ არ

იმყოფება ერთ წერტილში. დაწერეთ პროგრამა, რომელიც გამოითვლის ნახტომების

მაქსიმალურ რაოდენობას, რომლებიც შეიძლება კენგურუებმა გააკეთონ.

შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია ჰარით დაშორებული სამი

მთელი რიცხვი A, B და C (0 < A < B < C < 100) – კენგურუთა საწყისი კოორდინატები.

გამოსატანი მონაცემები: ერთადერთ სტრიქონში გამოიტანეთ ერთი მთელი რიცხვი -

ნახტომების მაქსიმალური რაოდენობა, რომლებიც შეიძლება კენგურუებმა გააკეთონ.

შესატანი მონაცემები გამოსატანი მონაცემები 2 3 5 1

3 5 9 3

ანალიზი. კენგურუთა თითოეული ნახტომის შემდეგ მათ შორის მანძილების ჯამი

მცირდება და ადრე თუ გვიან თამაში შეწყდება. თუ განვიხილავთ საწყის პოზიციაში ორი

კენგურუს კოორდინატებს, იოლი შესამჩნევია, რომ კენგურუებს შეუძლიათ მათ შორის

არსებულ თითოეულ წერტილში გააკეთონ ნახტომი. აქედან გამომდინარე, ამოცანა შეიძლება

ასე ამოიხსნას: დავადგინოთ საწყის ორ შუალედს შორის უდიდესი და გამოვაკლოთ 1, რადგან

კიდურა წერტილებში ნახტომების გაკეთება არ შეიძლება. #include <iostream>

int a,b,c;

main(){

cin>>a>>b>>c);

if (b-a>c-b) cout<<b-a-1; else cout<<c-b-1;

}

Page 20: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

20

ამოცანა 24. პოსტების რეიტინგი

Geolymp (2011 წელი, პირველი ეპიზოდი, ელდარ ბოგდანოვი)

ხშირად ფორუმებზე შეიძლება მომხმარებლის პოსტის სასარგებლოდ და

საწინააღმდეგოდ ხმის მიცემა. პოსტის საწყისი რეიტინგი 0-ის ტოლია. ცხადია, რომ რაც უფრო

მაღალი რეიტინგი აქვს პოსტს, იგი მით უფრო საინტერესო და სასარგებლოდ ითვლება.

ყველაზე საზიზღარი პოსტები კი უარყოფითი რეიტინგით გამოირჩევა.

ჩვენ ვიმყოფებით ისეთ ფორუმზე, სადაც დადებითი ხმა პოსტის რეიტინგს 2-ით ზრდის,

ხოლო უარყოფითი 1-ით ამცირებს. გვაქვს რაღაც პოსტი, რომლის მიმდინარე რეიტინგი არის R.

დაადგინეთ, მინიმუმ რამდენ ადამიანს უნდა მიეცა ხმა ამ პოსტისთვის ასეთი რეიტინგის

მისანიჭებლად. ერთ ადამიანს კონკრეტული პოსტისთვის ხმის მიცემა მხოლოდ ერთხელ

შეუძლია.

შესატანი მონაცემები: ერთადერთი სტრიქონი შეიცავს ერთ მთელ რიცხვს R (-100 ≤ R≤100).

გამოსატანი მონაცემები: დაბეჭდეთ მომხმარებლების ის მინიმალური რაოდენობა,

რომელიც საკმარისია პოსტისთვის R რეიტინგის მისანიჭებლად.

შესატანი მონაცემები გამოსატანი მონაცემები

7 5

განმარტება: თუ 4 მომხმარებელი მისცემს პოსტს დადებით ხმას, ხოლო 1 კი უარყოფითს,

მისი რეიტინგი 7-ის ტოლი გახდება.

ანალიზი. სულ განსახილველია 3 შემთხვევა: ა) შემოსატანი რიცხვი უარყოფითია. მაშინ

პოსტების მინიმალური რაოდენობა გვექნება იმ შემთხვევაში, თუ ყველა ხმა უარყოფითია და –1

ქულას იძლევა; ბ) შემოსატანი რიცხვი დადებითია და ლუწი. ამ შემთხვევაში მინიმალური

პასუხი მიიღწევა, თუ ყველა ხმა დადებითი იქნება, პოსტების რაოდენობა კი ქულათა ნახევრის

ტოლი იქნება; გ) შემოსატანი რიცხვი დადებითია და კენტი. დაიყვანება წინა შემთხვევაზე ერთი

უარყოფითი ხმის დამატებით.

#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" – წინააღმდეგ შემთხვევაში.

Page 21: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

21

შესატანი მონაცემები გამოსატანი მონაცემები 1 12 4 1 13 5 YES 1 12 4 0 15 2 NO

ანალიზი. შემოვიღოთ რაიმე დამხმარე ცვლადი, რომელსაც იმდენჯერ გავზრდით 1–ით,

რამდენი პირობაც შესრულდება.

#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“;

}

Page 22: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

22

ციკლის ოპერატორები

ციკლი წარმოადგენს ერთ-ერთ უმთავრეს სტრუქტურას პროგრამირებაში. მისი

საშუალებით ხდება პროგრამული კოდის გარკვეული ნაწილის მრავალჯერადი შესრულება,

სანამ მოცემული პირობა ჭეშმარიტია. თუკი მოცემული პირობა ყოველთვის ჭეშმარიტია, მაშინ

ციკლი უსასრულოდ იმუშავებს, ანუ პროგრამა “ჩაიციკლება”. С++-ში არსებობს ციკლის

სამნაირი კონსტრუქცია:

ციკლი for

ციკლი while

ციკლი do..while

უპირობო ციკლის ოპერატორი FOR

for ციკლს გააჩნია შემდეგ სინტაქსი:

for (ინიციალიზაციის გამოსახულება; პირობის გამოსახულება; ბიჯი) { ციკლის ტანი } ციკლის მუშაობის დროს უპირველესად სრულდება ინიციალიზაციის გამოსახულება, ანუ

ხორციელდება მნიშვნელობის მინიჭება ცვლადისათვის, რომელსაც ციკლის მთვლელს

უწოდებენ. ეს ხდება მხოლოდ ერთხელ - ციკლის დაწყების წინ. ამის შემდეგ ანალიზი

უკეთდება პირობის გამოსახულებას, რომელსაც ციკლის შეწყვეტის პირობასაც უწოდებენ. თუ

ეს პირობა თავიდანვე მცდარია, ან ციკლის მუშაობის პროცესში გახდება მცდარი, ციკლი აღარ

სრულდება და პროგრამა გადადის ციკლის მომდევნო პირველივე ოპერატორზე. თუ ციკლის

პირობა ჭეშმარიტია, მაშინ სრულდება ციკლის ტანში ჩაწერილი ოპერატორები, ხოლო ამის

შემდეგ ხდება ციკლის მთვლელის გაზრდა (ან შემცირება) ბიჯში მითითებული სიდიდით. თუ

ციკლის მთვლელის შეცვლის შემდეგ პირობა ისევ ჭეშმარიტია, ციკლის ტანი კიდევ ერთხელ

შესრულდება და ა.შ. პროგრამის მიერ ციკლის ტანის ერთხელ შესრულებას იტერაციას

უწოდებენ.

თუ ციკლის ტანი მხოლოდ ერთ ოპერატორს შეიცავს, დასაშვებია, რომ ის არ მოათავსოთ

ფიგურულ ფრჩხილებში, ხოლო თუ ციკლის ტანში ოპერატორების რაოდენობა 1-ზე მეტია,

ფიგურული ფრჩხილების გამოყენება აუცილებელია. წინააღმდეგ შემთხვევაში ციკლის ტანად

ჩაითვლება მხოლოდ ერთი – უახლოესი ოპერატორი.

მოვიყვანოთ for ციკლის ჩაწერის მაგალითი. ვთქვათ, გვინდა 7-ის ჯერადი ორნიშნა

რიცხვების გამოტანა ეკრანზე. 7-ის ჯერადი უმცირესი ორნიშნა რიცხვი 14-ია. თუ რაიმე

ცვლადს (პროგრმააში ციკლის მთვლელს) მივანიჭებთ 14-ს და შემდეგ მას ყოველ ბიჯზე

გავზრდით 7-ით, ცხადია, მივიღებთ ჩვენთვის სასურველ რიცხვებს. ციკლის მთვლელმა არ

უნდა გადააჭარბოს უდიდეს ორნიშნა რიცხვს - 99-ს. პროგრამულ კოდს ექნება სახე : for (i=14; i<=99; i=i+7)

cout<<i<<” “;

იგი გამოიტანს: 14 21 28 35 42 49 56 63 70 77 84 91 98.

თუ პირობა ციკლის დაწყებისთანავე დარღვეულია, მაშინ ციკლი საერთოდ არ

შესრულდება. მაგალითად, ციკლი x=10;

for(y=10; y>x; y++)

printf("%d ", y);

ერთხელაც არ შესრულდება, რადგან პირობა y>x; თავიდანვე დარღვეულია. მოყვანილ კოდში

x=10; ტოლობა საკმარისია შევცვალოთ x=9;–ით, რომ ციკლი მუშაობას დაიწყებს, თუმცა

მოხდება მეორე უკიდურესობა: ციკლის შეწყვეტის პირობა აღარასოდეს შესრულდება და

როგორც იტყვიან – პროგრამა „ჩაიციკლება“.

Page 23: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

23

უპირობო ციკლის ზოგადი კონსტრუქცია პროგრამირების ყველა ენაში თითქმის

ერთნაირია, მაგრამ 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;

ბოლო სტრიქონი გამოიწვევს შეცდომის შეტყობინებას, რადგან ციკლის ცვლადი ციკლის

შიგნითაა აღწერილი და ციკლის გარე ნაწილი მას ვერ ხედავს.

Page 24: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

24

ამოცანა 26. კენტი რიცხვების ჯამი

დაწერეთ პროგრამა, რომელიც გამოითვლის A-დან B-მდე ყველა კენტი რიცხვის ჯამს.

შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია ჰარით დაშორებული ორი

მთელი რიცხვი A და B (0 <= A, B <= 200) .

გამოსატანი მონაცემები: ერთადერთ სტრიქონში გამოიტანეთ ერთი მთელი რიცხვი – A-

დან B-მდე ყველა კენტი რიცხვის ჯამი.

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი

22 29 104

ანალიზი. შეგვიძლია დავწეროთ ციკლი A-დან B-მდე და თითოეული რიცხვი ამ

შუალედიდან შევამოწმოთ ლუწ–კენტობაზე. პროგრამა უფრო სწრაფად იმუშავებს თუ ციკლის

ცვლადის საწყის მნიშვნელობად შევარჩევთ პირველ კენტ რიცხვს მოცემული შუალედიდან (ის

ან a იქნება, ან a+1). ამის შემდეგ შეგვიძლია ციკლის ცვლადი ვზარდოთ 2-ის ტოლი ბიჯით.

#include <iostream>

int a,b,c,i;

main(){

cin>>a>>b;

for (i=a; i<=b; i++)

if (i%2==1)c=c+i;

cout<<c;

}

#include <iostream>

int a,b,c,i,k;

main(){

cin>>a>>b;

if (a%2==1) k=a; else k=a+1;

for (i=k; i<=b; i=i+2)

c=c+i;

cout<<c;

}

ამოცანა 27. გამყოფების რაოდენობა

მოცემულია მთელი N (0 < N < 30000) რიცხვი. დაწერეთ პროგრამა, რომელიც დაადგენს ამ

რიცხვის განსხვავებული გამყოფების რაოდენობას თავად ამ რიცხვისა და 1-ის ჩათვლით.

შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია ერთი მთელი რიცხვი N .

გამოსატანი მონაცემები: ერთადერთ სტრიქონში გამოიტანეთ ერთი მთელი რიცხვი – N–ის

გამყოფთა რაოდენობა.

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი

36 9

13 2

25 3

განმარტება: 36-ის გამყოფებია - 1, 2, 3, 4, 6, 9, 12, 18, 36. სულ მათი რაოდენობაა 9. 25-ის

გამყოფებია - 1, 5, 25.

ანალიზი. დავწეროთ ციკლი 1-დან შემომავალ რიცხვამდე და თითოეული რიცხვისათვის

ამ შუალედიდან, შევამოწმოთ ჰყოფს თუ არა ის შემომავალ რიცხვს უნაშთოდ. დადებითი

პასუხის შემთხვევაში რაიმე ცვლადი გავზარდოთ 1–ით და ამ ცვლადის საბოლოო მნიშვნელობა

იქნება ამოცანის პასუხი.

#include <iostream>

int a,c,i;

main(){

cin>>a;

for (i=1; i<= a; i++)

if (a%i==1)c++;

cout<<c;

}

Page 25: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

25

ამოცანა 28. Bedtime Reading - ძილის წინ საკითხავი

USACO 2006 წლის USA OPEN, “ბრინჯაოს” დივიზიონი

ფერმერი ჯონი ასრულებს თავის მოვალეობას: ძილის წინ წიგნები წაუკითხოს ბესის.

"ოჰ, ეს მე თავს მტკენს" - წუწუნებს ბესი.

"ეს ხომ უბრალო რიცხვთა თეორიაა" - პასუხობს ჯონი - "მოდი გავიაროთ კიდევ

ერთხელ. რიცხვის სიგმა ფუნქცია არის ამ რიცხვის გამყოფების ჯამი. მაგალითად,

12-ის გამყოფებია: 1, 2, 3, 4, 6 და 12. ამ რიცხვების შეკრებით მიიღება 28.

"სულ ეს არის" - კითხულობას ბესი – "იქნებ ვინმემ დაწეროს პროგრამა,

რომელიც იპოვის სიგმა ფუნქციას რიცხვისათვის I (1 <= I <= 1,000,000)."

შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია ერთი მთელი რიცხვი I .

გამოსატანი მონაცემები: ერთადერთ სტრიქონში გამოიტანეთ I-ს ყველა გამყოფის ჯამი.

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი

12 28

ანალიზი. ეს ამოცანა ძალიან წააგავს წინას, თუმცა მკვეთრად განსხვავდება შემოსატანი

მონაცემების დიაპაზონები (ერთგან შემოსატანი რიცხვი 30 ათასამდეა, ხოლო მეორეგან -

მილიონამდე). ამის გამო უმჯობესია, რომ ციკლის მუშაობის დრო შევამციროთ. ნებისმიერ

შედგენილ რიცხვს ერთი მაინც გამყოფი აქვს მის ფესვამდე (ანუ ისეთ რიცხვამდე, რომლის

თავის თავზე ნამრავლი განსახილველ რიცხვის ტოლია ან მაქსიმალურად უახლოვდება

ნაკლებობით). თუ ყველა გამყოფს ვიპოვით ფესვამდე, ცხადია, რომ მათი საშუალებით ვიპოვით

დანარჩენ გამყოფებსაც, რომლებიც ფესვიდან თავად ამ რიცხვამდე.

ქვემოთ იგივე და იგივე კოდი მოცემულია ორნაირად: მარცხენა მონაცემებს ღებულობს

სტანდარტულად (კლავიატურიდან) და შედეგი ეკრანზე გამოაქვს, მარჯვენა კი - ფაილიდან

კითხულობს და სხვა ფაილში ჩაწერს შედეგს.

#include < iostream >

main () {

int n, i, sum = 0;

cin>>n;

for (i = 1; i*i <= n; i++) {

if (n % i == 0) {

sum += i;

if (i*i<n) sum+= n/i;

}

}

Cout<<sum;

}

#include <stdio.h>

main () {

int n, i, sum = 0;

fin=fopen ("br1.in", "r");

fout=fopen ("br1.out", "w");

fscanf(fin, "%d", &n);

for (i = 1; i*i <= n; i++) {

if (n%i==0) {sum += i;

if (i*i<n) sum+=n/i;

}

}

fprintf (fout, "%d\n", sum);

}

ამოცანა 29. რიცხვების შებრუნება

მოცემულია ორნიშნა რიცხვებისაგან შედგენილი მიმდევრობა. თითოეული რიცხვი

შეაბრუნეთ და იმავე თანმიმდევრობით დაბეჭდეთ.

შესატანი მონაცემები: პირველ სტრიქონში მოცემულია ერთი მთელი რიცხვი n –

მიმდევრობის წევრთა რაოდენობა.

გამოსატანი მონაცემები: ერთადერთ სტრიქონში იმავე თანმიმდევრობით რიცხვების

შებრუნებული მნიშვნელობები. თუ ორნიშნა რიცხვი 0–ით ბოლოვდება, მისი შებრუნებული

რიცხვი ერთნიშნა ჩანაწერით გამოიტანეთ.

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი 6

15 92 70 44 27 30

51 29 7 44 72 3

Page 26: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

26

ანალიზი. მიმდევრობის რიცხვები წაკითხვისთანავე შევაბრუნოთ და დავბეჭდოთ.

რადგან ყველა რიცხვი ორნიშნაა, შებრუნება მარტივად ხდება 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;} }

ამოცანა 30. კოლოფი

ხორვატიის ღია პირველობა ინფორმატიკაში (2006/07 წელი, შეჯიბრი 4)

პატარა მირკომ ასანთის ღერები იატაკზე მოფანტა. დედა ძალიან გაჯავრდა ამის გამო და

მირკოს დაავალა, აეკრიფა ღერები და მართკუთხა ფორმის კოლოფში ჩაელაგებინა. მირკომ

შეამჩნია ყველა ასანთის ღერი არ თავსდება კოლოფში და გადაწყვიტა ასეთი ღერები მეზობლის

ნაგვის ყუთში ჩაეყარა, სადაც დედა ნამდვილად ვერ მიაგნებდა მათ.

დაეხმარეთ მირკოს დაადგინოს, თუ რომელი ღერები თავსდება კოლოფში. ასანთის ღერი

მხოლოდ მაშინ ითვლება კოლოფში მოთავსებულად, თუ მისი მთელი სიგრძე თავსდება

კოლოფის ფსკერზე. მირკო განიხილავს ასანთის ღერებს თანმიმდევრულად.

შესატანი მონაცემები: პირველ სტრიქონში მოცემულია სამი მთელი რიცხვი N (1 ≤ N ≤ 50) -

იატაკზე დაყრილი ასანთის ღერების რაოდენობა, W და H (1 ≤ W ≤ 100, 1 ≤ H ≤ 100) - კოლოფის

ზომები. მომდევნო N სტრიქონიდან თითოეულში მოცემულია მთელი რიცხვები 1-დან 100-მდე

დიაპაზონში, შესაბამისი ასანთის ღერის სიგრძე.

გამოსატანი მონაცემები: ყოველი ასანთის ღერისათვის თითო სტრიქონში

თანმიმდევრობით გამოიტანეთ სიტყვა “DA“ , თუ ასანთის ღერი თავსდება კოლოფში.

წინააღმდეგ შემთხვევაში გამოიტანეთ სიტყვა “NE”.

შესატანი მონაცემები გამოსატანი მონაცემი 5 3 4

3

4

5

6

7

DA

DA

DA

NE

NE

2 12 17

21

20

NE

DA

ანალიზი. ყველაზე გრძელი ასანთის ღერის სიგრძე, რომელიც შეიძლება მოთავსდეს

მართკუთხა ფორმის კოლოფში, იქნება კოლოფის მთავარი დიაგონალის სიგრძის ტოლი.

მთავარი დიაგონალის სიგრძის გამოსათვლელად გამოვიყენოთ პითაგორას თეორემა.

პროგრამის კოდში გამოყენებულია შედარების ოპერატორის გამარტივებული კონსტრუქცია,

რომელიც პირდაპირ printf ოპერატორშია ჩასმული. #include <cstdio>

int main( ) {

int n, w, h, k;

scanf( "%d%d%d", &n, &w, &h );

for( int i = 0; i < n; i++ ) {

scanf( "%d", &k );

printf( w*w+h*h >= k*k ? "DA\n": "NE\n" ); } }

Page 27: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

27

ამოცანა 31. Ice Cream - ნაყინი [Burch, 2001]

USACO 2001 წლის გაზაფხულის შეჯიბრი, “ნარინჯისფერი” დივიზიონი

როცა ფერმერი ჯონი კვებავს საკუთარ ძროხებს, გასართობად ერთგვარ თამაშსაც

თამაშობს. ის მიუყვება მწკრივში განლაგებულ ძროხებს და თანმიმდევრულად კითხულობს

მათ ყურებზე დაწერილ ნომრებს. ჯონი ცდილობს გამოიცნოს ლუწი ნომრებისაგან შედგენილი

ყველაზე გრძელი უწყვეტი მიმდევრობის სიგრძე და თუ ეს შეძლო, სადილის შემდეგ

უგემრიელეს ნაყინს მიიღებს.

მოცემულია ძროხათა რაოდენობა N (1 <= N <= 100,000) და N ცალი ნომერი დიაპაზონში

1..1,000,000. იპოვეთ ლუწი ნომრებით შედგენილი უგრძელესი უწყვეტი მიმდევრობის სიგრძე.

შესატანი მონაცემები: პირველ სტრიქონში მოცემულია ერთი მთელი რიცხვი N. მომდევნო

N სტრიქონიდან თითოეულში მოცემულია თითო მთელი რიცხვი - შესაბამისი ძროხის ნომერი.

გამოსატანი მონაცემები: ერთადერთ სტრიქონში გამოიტანეთ ერთი მთელი რიცხვი -

ლუწი ნომრებისაგან შედგენილი ყველაზე გრძელი უწყვეტი მიმდევრობის სიგრძე.

შესატანი მონაცემები გამოსატანი მონაცემი 7

1

2

4

6

3

4

12

3

ანალიზი. შემოვიღოთ რაიმე მთვლელი, რომელიც ყოველი ლუწი რიცხვის წაკითხვისას 1-

ით გაიზრდება, ხოლო ყოველი კენტი რიცხვის წაკითხვისას 0-ის ტოლი გახდება. რაიმე

ცვლადში დავიმახსოვროთ ამ მთვლელის მაქსიმალური მნიშვნელობა, რომელიც ამოცანის

პასუხიც იქნება. #include <iostream> using namespace std;

int n, w=0, h=0, k;

main() {

cin>>n;

for( int i = 0; i < n; i++ ) {

cin>>k;

if (k%2==0) h++; else h=0;

if (h>w) w=h;

}

cout<<w<<endl;

}

ამოცანა 32. გზის სწორი ნაწილი

ავარიული სიტუაციის გამო გადაწყდა თვითმფრინავი დასვან საავტომობილო

მაგისტრალზე, რომელიც შეიძლება წარმოვიდგინოთ, როგორც N თანაბარ ნაწილად დაყოფილი

მონაკვეთი. თითოეულ ნაწილს გააჩნია საკუთარი სიმაღლე. პილოტებს სჭირდებათ გზის

ყველაზე გზის ნაწილების ყველაზე გრძელი უწყვეტი მიმდევრობა, რომელშიც შემავალ

ნაწილებს ერთნაირი სიმაღლე აქვთ.

შესატანი მონაცემები: პირველ სტრიქონში მოცემულია ერთი მთელი რიცხვი N - გზის

ნაწილების რაოდენობა. მომდევნო N სტრიქონიდან თითოეულში მოცემულია თითო მთელი

დადებითი რიცხვი - შესაბამისი ნაწილის სიმაღლე.

გამოსატანი მონაცემები: ერთადერთ სტრიქონში გამოიტანეთ ერთი მთელი რიცხვი -

ერთნაირი სიმაღლის ნაწილებისაგან შედგენილი ყველაზე გრძელი უწყვეტი მიმდევრობის

სიგრძე.

Page 28: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

28

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი 13

5 5 6 7 7 7 7 6 6 5 4 4 4

4

ანალიზი. საჭიროა ერთმანეთს შევადაროთ ყველა მეზობელი შემომავალი რიცხვი.

ამისთვის საჭიროა ორი ცვლადი: ერთში (კოდში current ცვლადითაა აღნიშნული) ჩაიწერება

მიმდინარე ნაწილის მნიშვნელობა, ხოლო მეორეში – წინა მეზობლის მნიშვნელობა (კოდში -

old ცვლადი). თუ ისინი ტოლია, რაიმე მთვლელი გავზარდოთ 1-ით, წინააღმდეგ შემთხვევაში

მთვლელს მივანიჭოთ 1. რაიმე ცვლადში დავიმახსოვროთ ამ მთვლელის მაქსიმალური

მნიშვნელობა, რომელიც საბოლოოდ ამოცანის პასუხი იქნება. ციკლის ბოლოს old-ს

მივანიჭოთ current.

#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-იც იყოს.

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი 4

0 3

2 5

4 2

4 0

6

Page 29: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

29

განმარტება. თავიდან ტრამვაი ცარიელია და პირველ გაჩერებაზე მასში ადის 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;

}

ამოცანა 34 – ნორჩი ფიზიკოსი

http://codeforces.com/problemset/problem/69/A

ფიზიკის მასწავლებელმა ვასოს მისცა ერთი შეხედვით მარტივი ამოცანა: მოცემულია

სხეული სივრცეში და მასზე მოქმედი ძალები. სხეული შეიძლება ჩავთვალოთ მატერიალურ

წერტილად (0,0,0) კოორდინატებით. ვასომ უნდა დაადგინოს იმყოფება თუ არა სხეული

წონასწორობაში.

ვასომ იცის, რომ საკმარისია შემოწმდეს, არის თუ არა ყველა ვექტორის ჯამი 0 და დაიწყო

ამოცანის ამოხსნა, მაგრამ აღმოჩნდა, რომ მოქმედი ძალები ძალიან ბევრია. დაეხმარეთ ვასოს და

დაწერეთ პროგრამა, რომელიც დაადგენს, არის თუ არა სხეული წონასწორობაში.

შესატანი მონაცემები: პირველ სტრიქონში მოცემულია ერთი მთელი რიცხვი n (1≤n≤100).

მომდევნო n სტრიქონიდან თითოეულში მოცემულია სამ-სამი მთელი რიცხვი: xi, yi, zi – ძალები,

რომელიც მოქმედებენ შესაბამისად x, y, და z ღერძების გასწვრივ (-100≤xi,yi,zi≤100).

გამოსატანი მონაცემები: ერთადერთ სტრიქონში გამოიტანეთ სიტყვა "YES", თუ სხეული

იმყოფება წონასწორობაში ან სიტყვა "NO" – წინააღმდეგ შემთხვევაში.

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი 3

4 1 7

-2 4 -1

1 -5 -3

NO

3

3 -1 7

-5 2 -4

2 -1 -3

YES

ანალიზი. ეს ამოცანა წინა ამოცანის მსგავსია, ოღონდ აქ 3 სხვადასხვა ცვლადში უნდა

დავიმახსოვროთ შესაბამისი ღერძების გასწვრივ მოქმედი ძალების ჯამები.

Page 30: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

30

#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"; }

ამოცანა 35. მე-13 კორპუსი

Geolymp (2011 წელი, მესამე ეპიზოდი, ელდარ ბოგდანოვი)

ერთ-ერთ პატარა, მაგრამ სწრაფად განვითარებად ქალაქში ააშენეს ცათამბჯენების

კომპლექსი და შენობები გადანომრეს ნატურალური რიცხვებით. იმ შენობის მაცხოვრებლები,

რომელსაც მე-13 ნომერი ხვდა წილად, ისედაც არ არიან ბედნიერები და წარმოიდგინეთ მე-13

სართულზე ხალხი რა დღეშია. უფრო მეტად, ამ კორპუსის 13-ის ყოველ ჯერად (13, 26, 39, 52, ...)

სართულზე ხალხი ძალზედ უკმაყოფილოა შექმნილი ვითარებით. ამიტომ იყო მიღებული

გადაწყვეტილება, სართულების დანომვრაში არ გამოეყენათ 13-ის ჯერადი რიცხვები. იმ

სართულს, რომელიც მიწიდან გადათვლით მე-13 არის, მე-14 დაარქვეს, მაგის შემდეგს - მე-15

და ასე შემდეგ. მიწიდან 25-ე სართული უკვე ნომერ 27-ს ატარებს.

თქვენ მოცემული გაქვთ სართულის მიწიდან გადათვლილი ნომერი N. დაადგინეთ მისი

ნომერი მე-13 კორპუსის მაცხოვრებელთა სისტემაში.

შესატანი მონაცემები: ერთადერთი სტრიქონი შეიცავს ერთადერთ მთელ რიცხვს -

მიწიდან გადათვლილ სართულის ნომერს N.

გამოსატანი მონაცემები: ერთადერთ სტრიქონში გამოიტანეთ ერთი მთელი რიცხვი –

სართულის ნომერი მე-13 კორპუსის მაცხოვრებელთა სისტემაში.

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი 15 16

ანალიზი. შევასრულოთ ციკლი 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;

}

Page 31: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

31

ოპერატორები WHILE, DO/WHILE - ციკლი პირობით

პროგრამირებაში ხშირია შემთხვევები, როცა ციკლის განმეორებათა რიცხვი წინაწარ

უცნობია. ამ დროს for ციკლის გამოყენება არაეფექტურია და მის ნაცვლად გამოიყენება

კონსტრუქცია while ან do/while. მათი ჩაწერის სინტაქსია:

while (პირობა) {

ციკლის ტანი

}

do{

ციკლის ტანი

} while (პირობა);

ამ ორ კონსტრუქციას შორის ერთადერთი განსხვავებაა: while ციკლში ჯერ მოწმდება

პირობა და მისი ჭეშმარიტების შემთხვევაში სრულდება ციკლის ტანი, ხოლო do/while ციკლში

ციკლის ტანი ერთხელ მაინც სრულდება, თუნდაც პირობა მცდარი იყოს. სხვაგვარად რომ

ვთქვათ, პირობა მოწმდება ციკლის ბოლოს და თუ ის მცდარია, პროგრამა გამოდის ციკლიდან

და ასრულებს მის მომდევნო ოპერატორს.

სხვა ყველა თვისება ამ ციკლებს ერთნაირი აქვთ. ციკლის ტანში უნდა ხდებოდეს რაიმე

ისეთი ქმედება, რომ პირობა გარკვეულ მომენტში დაირღვეს. წინააღმდეგ შემთხვევაში

პროგრამა ჩაიციკლება. თუ ციკლის ტანი ერთზე მეტ ოპერატორს შეიცავს, აუცილებელია მისი

მოთავსება ფიგურულ ფრჩხილებში.

ამოცანა 36. ციფრთა ჯამი

მოცემულია მთელი რიცხვი N (1<N<2,000,000,000). დაწერეთ პროგრამა, რომელიც

გამოთვლის მის ციფრთა ჯამს.

შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია ერთი მთელი რიცხვი N .

გამოსატანი მონაცემები: ერთადერთ სტრიქონში გამოიტანეთ ერთი მთელი რიცხვი – N–ის

ციფრთა ჯამი.

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი

234543082 31

ანალიზი. 10-ზე გაყოფის ნაშთით შეგვიძლია გავიგოთ რიცხვის ერთეულთა თანრიგში

მდგომი ციფრი და დავუმატოთ ის რაიმე ცვლადს. ამის შემდეგ 10–ზე მთელი გაყოფით ეს

ციფრი შეიძლება მოვაშოროთ რიცხვს და პროცესი გავიმეოროთ მანამ, ვიდრე საწყისი რიცხვი 0

არ გახდება. #include <iostream>

using namespace std;

int a,c,i;

main(){

cin>>a;

while(a>0){

c=c+a%10; a=a/10; } cout<<c;

}

ამოცანა 37. 3*N+1

ნატურალურ რიცხვ N-ისათვის აწარმოებენ შემდეგ ორ ოპერაციას: ა) თუ რიცხვი ლუწია,

ჰყოფენ 2-ზე. ბ) თუ რიცხვი კენტია, ამრავლებენ 3-ზე და უმატებენ ერთს. შემდეგ იგივე

ოპერაციას იმეორებენ მიღებულ რიცხვზე მანამ, ვიდრე რომელიმე ოპერაციის შემდეგ 1-ს არ

მიიღებენ (მათემატიკურად დამტკიცებულია, რომ 1 ნებისმიერი ნატურალური რიცხვისაგან

დაწყების შემთხვევაში მიიღება). დაწერეთ პროგრამა, რომელიც პირველ სტრიქონში გამოიტანს

ზემოთ ნაჩვენები პროცესის დროს მიღებულ ყველა რიცხვს, ხოლო მეორეში - შესრულებულ

ოპერაციათა რაოდენობას.

შესატანი მონაცემები: ერთი მთელი რიცხვი N (0<N<30000).

Page 32: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

32

გამოსატანი მონაცემები: პირველ სტრიქონში გამოიტანეთ იმ რიცხვთა მიმდევრობა,

რომლებიც მიიღებიან ვიდრე საწყისი რიცხვი 1 არ გახდება. მეორე სტრიქონში გამოიტანეთ

ერთი მთელი რიცხვი – პირველ სტრიქონში გამოტანილ რიცხვთა რაოდენობა.

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი

23 70 35 106 53 160 80 40 20 10 5 16 8 4 2 1

15

ანალიზი. სხვადასხვა რიცხვისათვის ჩასატარებელი ოპერაციების რაოდენობა სხვადასხვა

იქნება. ამიტომ for ოპერატორით ამ ამოცანის ამოხსნა პრობლემებს შექმნის. შევასრულოთ

ციკლი მანამ, ვიდრე შემომავალი რიცხვი 1–ის ტოლი არ გახდება. N–ის მიმდინარე

მნიშვნელობები ციკლის შიგნით დავბეჭდოთ, ხოლო ჩატარებული ოპერაციების რაოდენობა,

რომელსაც ამოცანაში k ცვლადი ითვლის, – ციკლის გარეთ.

#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;

}

ამოცანა 38. უახლოესი 2–ის ხარისხები

დაწერეთ პროგრამა, რომელიც მოცემული მთელი N (0<N<30000) რიცხვისთვის გამოიტანს

2–ის უახლოეს ორ ხარისხს: ნაკლებობით და მეტობით.

შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია ერთი მთელი რიცხვი N,

რომელიც არ წარმოადგენს 2–ის ხარისხს.

გამოსატანი მონაცემები: ერთადერთ სტრიქონში გამოიტანეთ ორი მთელი რიცხვი – N–ის

უახლოესი 2–ის ხარისხები ზრდადობით დალაგებული.

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი

27 16 32

ანალიზი. რაიმე ცვლადს (ვთქვათ, c–ს) მივანიჭოთ 1 და ციკლში მანამდე ვამრავლოთ 2–

ზე, ვიდრე ის შემოსატან რიცხვზე მეტი არ გახდება. ციკლის დასრულების შემდეგ c–ს ექნება

გამოსატანი ორი რიცხვიდან უდიდესის მნიშვნელობა. სიდიდით ნაკლები 2–ის ხარისხი კი

მიიღება c–ს ორზე გაყოფით.

#include <iostream>

using namespace std;

int a,c=1;

main(){

cin>>a;

while(a>c){

c=c*2; }

cout<<c/2<<” “<<c;

}

Page 33: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

33

ამოცანა 39. 2–ის ხარისხების ჯამი

ცნობილია, რომ ნებისმიერი მთელი რიცხვი შეიძლება წარმოვადგინოთ როგორც 2–ის

ხარისხების ჯამი. დაწერეთ პროგრამა, რომელიც მოცემული მთელი N (0<N<30000)

რიცხვისთვის გამოიტანს კლებადობით დალაგებულ შესაბამის 2–ის ხარისხებს.

შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია ერთი მთელი რიცხვი N .

გამოსატანი მონაცემები: ერთადერთ სტრიქონში გამოიტანეთ შესაბამისი 2–ის ხარისხები.

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი

62 32 16 8 4 2

128 128

1057 1024 32 1

ანალიზი. ზოგადად ეს ამოცანა უკავშირდება მოცემული რიცხვის ორობით სისტემაში

გადაყვანას (იხ. თავი „თვლის სისტემები“) და იგი ეფექტურად იხსნება რეკურსიული

ალგორითმებით, თუმცა შესაძლებელია სხვაგვარი მიდგომის გამოყენებაც. ციკლით ვიპოვოთ

მოცემულ რიცხვზე ნაკლები უახლოესი 2–ის ხარისხი. ამის შემდეგ გავხსნათ მეორე ციკლი და

ვიდრე მოცემული რიცხვი 0 არ გახდება, გამოვაკლოთ მას 2–ის ის ხარისხები, რომლებიც

ციკლის შესაბამის ბიჯზე მოცემულ რიცხვზე ნაკლები აღმოჩნდება. #include <iostream>

using namespace std;

int a,c=1;

main(){

cin>>a;

while(a>=c){ c=c*2;}

c=c/2;

while(a>0){

if (a>=c) {a=a-c; cout<<c/2; }

}

ამოცანა 40. სუპერკენგურუ

(საქართველოს მოსწავლეთა ოლიმპიადა, რეგიონული ტური)

ხელოვნური ინტელექტის პრობლემებზე მომუშავე მეცნიერებმა შექმნეს კენგურუს

ინტელექტის დონის მქონე რობოტი, რომელსაც სახელად “სუპერკენგურუ” დაარქვეს.

კენგურუს ანალოგიით მისი მოძრაობის ალგორითმი აგებულია ნახტომებზე. ამასთან,

მიზნისაკენ მიმავალ გზას იგი განიხილავს რიცხვით ღერძად, რომლის ნულოვან წერტილში

თავად დგას, ხოლო მიზანი განთავსებულია N-ურ წერტილში. სუპერკენგურუ მიზნისაკენ

მოძრაობს წრფივად, წარმოსახვითი რიცხვითი ღერძის გასწვრივ. პირველი ნახტომის სიგრძე 1

ერთეულია, ხოლო ყოველი მომდევნო ნახტომის სიგრძე წინაზე ორჯერ მეტია. თუკი მორიგი

ნახტომის დროს სუპერკენგურუ გადაახტა მიზანს, მაშინ ის იცვლის მიმართულებას 180

გრადუსით და თავიდან იწყებს ნახტომების კეთებას, ანუ ჯერ ხტება 1 ერთეულზე, მერე 2, 4, 8

და ა.შ. მიზანი მიღწეულად ითვლება მხოლოდ მაშინ, როდესაც სუპერკენგურუ მოხვდება N-ურ

წერტილში.

დაწერეთ პროგრამა, რომელიც მოცემული N რიცხვისათვის (0<=N<=1,000,000,000),

გამოთვლის მიზნამდე მისასვლელ ნახტომების რაოდენობას.

შესატანი მონაცემები: ერთადერთ სტრიქონში ერთი მთელი N რიცხვი – მანძილი

სუპერკენგურუსა და მიზანს შორის.

გამოსატანი მონაცემები: ერთადერთ სტრიქონში იწერება ერთადერთი რიცხვი –

ნახტომების რაოდენობა.

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი

11 9

Page 34: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

34

განმარტება. რიცხვით ღერძზე სუპერკენგურუს მიერ განვლილი წერტილებია:

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;

}

ამოცანა 41. მარტივი მამრავლები

დაწერეთ პროგრამა, რომელიც მოცემული მთელი N (1 < N < 30000) რიცხვისათვის

გამოიტანს ზრდადობით დალაგებულ მის ყველა მარტივ მამრავლს.

შესატანი მონაცემები: ერთადერთ სტრიქონში ერთი მთელი რიცხვი – N.

გამოსატანი მონაცემები: ერთადერთ სტრიქონში გამოიტანეთ ზრდადობით დალაგებული

N–ის ყველა მარტივ მამრავლი, რომლებიც ჰარით იქნებიან გაყოფილი.

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი

140 2 2 5 7

13 13

8 2 2 2

ანალიზი. დიდი რიცხვებისათვის ეს ამოცანა არცთუ ტრივიალურია, მაგრამ ჩვენს

შემთხვევაში მითითებული დიაპაზონი საშუალებას იძლევა ასეთი ალგორითმი გამოვიყენოთ:

დავიწყოთ უმცირესი შესაძლო გამყოფიდან – 2–დან და ვიდრე მოცემული რიცხვი 2–ზე იყოფა,

დავბეჭდოთ 2, ხოლო მოცემული რიცხვი შევამციროთ 2–ჯერ. თუკი რიცხვი უნაშთოდ აღარ

იყოფა 2–ზე, გამყოფი გავზარდოთ 1–ით და იგივე გავიმეოროთ ვიდრე შემომავალი რიცხვი

ერთის ტოლი არ გახდება. #include <iostream>

using namespace std;

int a,c=2; main(){

cin>>a;

while(a>1){

if (a%c==0) {a=a/c; cout<<c<<” “;} else c++;

}

}

Page 35: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

35

ამოცანა 42. მიკრობები.

http://codeforces.com/problemset/problem/198/A

რეინჯერმა იცუკენმა მიიღო მორიგი სამთავრობო დავალება და გაემგზავრა პლანეტა

მარსზე, სადაც უნდა ჩაატაროს ცდები იქაურ ბაქტერიებზე, რომლებსაც ფრიად უცნაური

თვისებები აღმოაჩნდათ. პირველი ცდის დაწყებისას სინჯარაში მხოლოდ ერთი ბაქტერიაა.

წამის განმავლობაში თითოეული ბაქტერია იყოფა k ბაქტერიად, რის შემდეგაც ანომალიური

ეფექტების შედგად სინჯარაში ჩნდება კიდევ b ბაქტერია. ამრიგად, თუკი რომელიმე წამის

დასაწყისში სინჯარაში იყო x ცალი ბაქტერია, ამ წამის დასრულებისას იარსებებს k*x + b

ცალი ბაქტერია. ცდებმა აჩვენეს, რომ n წამის შემდეგ ბაქტერიების რაოდენობა გახდება

ზუსტად z ცალი და ამით ცდა დასრულებულად ითვლება.

მეორე ცდის დაწყების წინ სინჯარას უტარდება დეზინფექცია და ამის შემდეგ მასში

თავსდება t ცალი ბაქტერია. იცუკენს აინტერესებს, რამდენი წამის შემდეგ გახდება ბაქტერიების

რაოდენობა z–ზე არანაკლები. ბაქტერიები მეორე ცდის დროსაც იმავე პრინციპით

მრავლდებიან, როგორც პირველი ცდისას.

დაეხმარეთ იცუკენს და დაადგინეთ წამთა მინიმალური რაოდენობა, რომლის შემდეგაც

ბაქტერიების რაოდენობა გახდება z–ზე არანაკლები.

შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია ოთხი მთელი რიცხვი –

შესაბამისად, k, b, n და t (1 ≤ k, b, n, t ≤ 106)

გამოსატანი მონაცემები: ერთი მთელი რიცხვი: წამთა მინიმალური რაოდენობა, რომლის

შემდეგაც ბაქტერიების რაოდენობა გახდება z–ზე არანაკლები.

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი 3 1 3 5 2

1 4 4 7 3

2 2 4 100 0

ანალიზი. რადგან z მილიონს არ აღემატება, საკმარისია მოხდეს პროცესის სიმულაცია. #include <iostream>

using namespace std;

main(){

int n,t,k,b,j=0;

cin>>k>>b>>n>>t;

long long l=1;

while (l<=t) {l*=k; l+=b; j++; }

j--;

if (n>j) cout<<n-j; else cout<<0;

}

ამოცანა 43. Symmetry - სიმეტრია [Jeffrey Wang, 2009]

USACO, 2011 წლის იანვრის შეჯიბრი, “ბრინჯაოს” დივიზიონი

ფერმერ ჯონს უყვარს სიმეტრია და ახლა ის ათავსებს საკუთარ ძროხებს NxM უჯრედის

შემცველ მართკუთხა არეზე (1<=N<= 1,000,000,000; 1<=M<=1,000,000,000).

სიმეტრიული განლაგების მისაღებად ფჯ შემდეგნაირად იქცევა: ის განათავსებს ძროხას

მართკუთხა არის ცენტრალურ უჯრედში (თუკი ასეთი არ არსებობს, პროცესი წყდება). შემდეგ

ჯონი არეს ჰყოფს ოთხ მცირე ზომის არედ, რომლებიც ერთმანეთის გაყოფილი არიან არჩეული

უჯრედის შემცველი ჰორიზონტალით და ვერტიკალით. ამის შემდეგ ფჯ იგივე პროცესს

იმეორებს ახალი არეების მიმართ, ვიდრე ცენტრალური უჯრედი აღარ იარსებებს ან მიღებული

არე ვეღარ გაიყოფა 4 ქვეარედ.

მაგალითად, თუ N=7 და M=15, ჯონი განათავსებს ძროხას (4,8) უჯრედში, რომელიც

გაჰყოფს საწყის არეს 3х7 ზომის ოთხ ქვეარედ. შემდეგ ამ ოთხი ქვეარიდან თითოეულში ჯონი

განათავსებს ძროხას (2,4) უჯრედში, რაც გამოიწვევს თითოეული ქვეარის გაყოფას 1х3 ზომის

ოთხ ახალ ქვეარედ და ა.შ. ეს პროცესი ნაჩვენებია ქვემოთ (ძროხები აღნიშნულია С–თი):

Page 36: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

36

............... ............... .......|....... .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.

ასეთი ზომის არისათვის ფერმერ ჯონს დასჭირდება 21 ძროხა.

მეორეს მხრივ, თუ N=M=5, საჭირო იქნება სულ 1 ძროხა, რადგან ცენტრში მისი

განთავსების შემდეგ არე გაიყოფა 2х2 ზომის ოთხ ქვეარედ, რომლებსაც უკვე აღარ ექნებათ

ცენტრალური უჯრედი.

დაეხმარეთ ჯონს იმის გარკვევაში, თუ რამდენი ძროხაა საჭირო.

შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია ორი მთელი რიცხვი – N და M.

გამოსატანი მონაცემები: ერთი მთელი რიცხვი – ძროხათა საჭირო რაოდენობა.

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი

7 15 21

ანალიზი. ცენტრალური უჯრედი არეს გააჩნია მხოლოდ მაშინ, თუ მისი ორივე

განზომილება ერთდროულად არის კენტი. ამასთან, ყოველი გაყოფა თითოეულ განზომილებას

2–ჯერ ამცირებს. აქედან გამომდინარე, არეთა გაყოფის პროცესი გაგრძელდება მანამ, ვიდრე N

და M ერთდროულად არიან კენტები 2–ზე გაყოფისას. #include <iostream>

using namespace std;

int N, M; long long total; int main () { cin>>N>>M; while (N%2 && M%2) { total = 4 * total + 1; N /= 2; M /= 2; } cout<<total; }

ამოცანა 44. პასკალი

ხორვატიის ღია პირველობა ინფორმატიკაში (2007/08 წელი, შეჯიბრი 5)

ფრანცი მეათე კლასშია, თუმცა ჯერ კიდევ პასკალს სწავლობს. მასწავლებელმა საშინაო

დავალებად მას ნოუთბუქში ჩაუწერა ქვემოთ მოყვანილი პროგრამული კოდი და დაავალა

გაერკვია გამოსატანი მნიშვნელობა მოცემული N–სათვის. readln(N);

counter := 0;

for i := N-1 downto 1 do begin

counter := counter + 1;

if N mod i = 0 then break;

end;

writeln(counter);

დაწერეთ პროგრამა, რომელიც ამოხსნის ფრანცის ამოცანას.

შენიშვნა: პასკალზე readln არის შეტანის ოპერატორი, writeln – გამოტანის

ოპერატორი, ხოლო break იწვევს ციკლის შეწყვეტას და გადასვლას მომდევნო ოპერატორზე.

შესატანი მონაცემები: ერთი მთელი რიცხვი – N (1 ≤ N ≤ 109).

გამოსატანი მონაცემები: ერთი მთელი რიცხვი – ფრანცის ამოცანის პასუხი.

Page 37: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

37

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი 1 0

10 5

27 18

ანალიზი. პირველ რიგში დასადგენია პასკალზე დაწერილი კოდის შინაარსი. ცვლადი

counter იზრდება ერთით მანამ, ვიდრე არ ვიპოვით N–ის უდიდეს გამყოფს. უფრო ზუსტად

რომ ვთქვათ, პროგრამა პოულობს რიცხვისა და მისი უდიდესი გამყოფის სხვაობას (ცხადია,

გამყოფებში თავად ეს რიცხვი არ იგულისხმება). ამ პროგრამის რეალიზაცია ბევრნაირად

შეიძლება. გთავაზობთ ერთ–ერთ მათგანს.

#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;

}

ამოცანა 45. ვინი პუჰი და თაფლი

http://codeforces.com/problemset/problem/120/C

ყველამ იცის, თუ როგორ უყვარს თაფლი ვინი პუჰს. მან და გოჭმა გაიგეს, რომ კურდღელს

ისევ გაუჩნდა თაფლის დიდი მარაგი და სასწრაფოდ ესტუმრნენ მას. და აი, ვინი პუჰის წინ

მწკრივში დგას n ცალი თაფლიანი ქილა. i–ურ ქილაში ai კილოგრამი თაფლია. ვინი ჭამს

თაფლს შემდეგი წესით: ის ყოველთვის ირჩევს ქილას, რომელშიც ყველაზე მეტი თაფლია (თუ

ასეთი ქილა რამდენიმეა, ირჩევს ნებისმიერს). თუ ამ ქილაში k კილოგრამზე ნაკლები თაფლია,

ან ვინიმ უკვე სამჯერ ჭამა ამ ქილიდან, მაშინ მას გოჭს გადასცემს, წინააღმდეგ შემთხვევაში კი

ჭამს k კილოგრამ თაფლს ამ ქილიდან და შემდეგ უკან აბრუნებს მწკრივში. ვინი აგრძელებს ამ

პროცესს მანამ, ვიდრე ყველა ქილას არ მისცემს გოჭს. გამოთვალეთ ჯამურად რამდენ

კილოგრამ თაფლს მიიღებს გოჭი.

შესატანი მონაცემები: პირველ სტრიქონში ორი მთელი რიცხვი – n და k (1≤n≤100,

1≤k≤100). მეორე სტრიქონში n ცალი მთელი a1, a2, ..., an, (1≤ai≤100).

გამოსატანი მონაცემები: ერთი მთელი რიცხვი – რამდენი კილოგრამი თაფლი შეხვდა

გოჭს.

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი 3 3

15 8 10 9

ანალიზი. იმ ფაქტს, რომ ვინი პუჰი ირჩევს ქილას ყველაზე მეტი თაფლით, ამოცანის

ამოხსნისათვის არავითარი მნიშვნელობა არ აქვს, რადგან იგივე ქილა სხვა თანმიმდევრობითაც

რომ აეღო, მაინც იმავე რაოდენობს თაფლს დაუტოვებდა მასში გოჭს. აქედან გამომდინარე

თითოეული ქილისათვის მხოლოდ ის არის დასადგენი, ვინი მისგან 3*k რაოდენობის თაფლს

შეჭამს, თუ x%k რაოდენობის თაფლს დატოვებს.

Page 38: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

38

#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;

}

ამოცანა 46. პოზიცია

(ბულგარეთი, ზამთრის შეჯიბრი ინფორმატიკაში, 7–8 კლასი, 2010)

პეშო და გოშო თამაშობენ შემდეგ თამაშს: მათ ერთმანეთს თანმიმდევრობით მიუწერეს

მთელი დადებითი რიცხვის კვადრატები – 1491625364964.... და ახლა აინტერესებთ,

რომელი ციფრი იქნება მოცემული პოზიციაზე ამ მიმდევრობაში. რადგან მიმდევრობა სწრაფად

გაიზარდა, გამოთვლები გართულდა. დაწერეთ პროგრამა, რომელიც დაეხმარება მათ.

შესატანი მონაცემები: პირველ სტრიქონში ერთი მთელი რიცხვი – k (0<k<3200000).

გამოსატანი მონაცემები: ერთი მთელი რიცხვი – k პოზიციაზე მყოფი რიცხვი.

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი 4 1

13 4

ანალიზი. ამოცანა სხვადასხვანაირად შეიძლება ამოიხსნას. ერთ–ერთი გზაა, ჯერ

დავადგინოთ რომელი რიცხვის კვადრატში მოხვდება მოცემული პოზიცია, ხოლო შემდეგ უკვე

ამ რიცხვის შიგნით დავადგინოთ შესაბამისი ციფრი.

#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;

}

Page 39: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

39

თეორიული ამოცანა ევკლიდეს ალგორითმი

ევკლიდეს ალგორითმი პოულობს ორი რიცხვის უდიდეს საერთო გამყოფს. არსებობს ამ

ალგორითმის ორი ვარიანტი: სხვაობიანი და ნაშთიანი. სხვაობიანი ალგორითმი

დაფუძნებულია იმ ფაქტზე, რომ a და b (a>b) რიცხვების უდიდესი საერთო გამყოფი იგივეა რაც

a-b და b რიცხვების უდიდესი საერთო გამყოფი. ნაშთიანი ალგორითმი იგივე ლოგიკით

მუშაობს, ოღონდ სხვაობის ნაცვლად a%b ნაშთს იყენებს. თუკი a და b რიცხვები

ურთიერთმარტივები არიან, მაშინ ალგორითმი პასუხად 1-ს მიიღებს. ნაშთიანი ალგორითმი

სხვაობიანზე გაცილებით სწრაფი და ეფექტურია. ქვემოთ მოყვანილია ორივე მათგანის კოდი

და მუშაობა ბიჯების მიხედვით a=7222 და b=1727 რიცხვებისათვის.

ნაშთიანი ალგორითმი სხვაობიანი ალგორითმი #include<iostream>

using namespace std;

int a,b,c;

main(){

cin>>a>>b;

while ( b>0) {

c = a % b;

a = b;

b = c;

}

cout<<a;

}

#include<iostream>

using namespace std;

int a,b;

main(){

cin>>a>>b;

while ( a != b) {

if (a > b) a -= b;

else b -= a;

}

cout<<a;

}

7222 1727

1727 314

314 157

157 0

7222 1727

5495 1727

3768 1727

2041 1727

314 1727

314 1413

314 1099

314 785

314 471

314 157

157 157

ამოცანა 47. განძისმაძიებელი

(ბულგარეთი, ზამთრის შეჯიბრი ინფორმატიკაში, 2010 წელი, 6 კლასი)

ნორჩმა განძზე მონადირე რუმენმა აირჩია სპეციალობა „განძისმაძიებლობა“ და ზამთრი

პრაქტიკებს ველიკო ტერნოვოს გათხრებზე ატარებს. პრაქტიკა გრძელდება b დღე. რუმენი

ყოველდღე პოულობს a ნამარხ მონეტას. პირველი დღის ბოლოს მას აქვს a მონეტა, მეორეს

დღის ბოლოს – 2*a მონეტა, ხოლო პრაქტიკის უკანასკნელი დღის ბოლოს b*a მონეტა.

თუკი რომელიმე დღის ბოლოს რუმენის მიერ ნაპოვნი მონეტების საერთო რაოდენობა

უნაშთოდ გაიყოფა b–ზე, მაშინ ხელმძღვანელი ჩუქნის მას შოკოლადს. რუმენი დაუყოვნებლივ

ჭამს შოკოლადს და ახლა სურს, რომ დაწეროთ პროგრამა, რომელიც გამოითვლის, თუ რამდენ

შოკოლადს შეჭამს რუმენი პრაქტიკის ბოლომდე.

შესატანი მონაცემები: პირველ სტრიქონში ორი მთელი რიცხვი – a და b(1≤a,b≤109).

გამოსატანი მონაცემები: ერთი მთელი რიცხვი – შოკოლადების რაოდენობა, რომელიც

რუმენს ერგება პრაქტიკის განმავლობაში.

Page 40: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

40

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი 2 1 1

2 2 2

5 4 1

5 10 5

ანალიზი. მათემატიკურად შეიძლება დამტკიცდეს, რომ ამ ამოცანის ამოხსნას

წარმოადგენს a და b რიცხვების უდიდესი საერთო გამყოფი, რომელიც შეიძლება ვიპოვოთ

ევკლიდეს ალგორითმით. #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 ნომერზე მყოფი რიცხვი.

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი

2 6

6 606

ანალიზი. იოლი შესამჩნევია, რომ მრგვალი რიცხვების მიმდევრობა ჰგავს მთელი

რიცხვების ორობითი ჩანაწერების მიმდევრობას. რადგან მიმდევრობა ნულით იწყება, ხოლო

გადანომვრა – ერთით, შემოსატან რიცხვს 1 გამოვაკლოთ, გადავიყვანოთ ორობით სისტემაში და

1–იანები 6–ით შევცვალოთ.

#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;

}

Page 41: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

41

ამოცანა 49. მართკუთხედი

(ლატვიის ოლიმპიადა ინფორმატიკაში, მეორე ეტაპი, 1998)

ვილიბალდმა გადაწყიტა კვადრატებად დაჭრას n×m ზომის მართკუთხა უჯრედოვანი

ფურცელი. ის ერთი გაჭრით ღებულობს ფურცლიდან რაც შეიძლება დიდი ზომის კვადრატს,

შემდეგ ამ კვადრატს ინახავს, ხოლო ფურცლის დარჩენილ ნაწილზე იგივე მოქმედებას

იმეორებს. ვილიბალდი ამ ქმედებას იმეორებს მანამ, ვიდრე ფურცლის დარჩენილი ნაწილიც

კვადრატი არ გახდება

დაწერეთ პროგრამა, რომელიც მოცემული n და m (n<10000, m<10000)

რიცხვებისთვის გამოითვლის, თუ რამდენ კვადრატს მიიღებს ვილიბალდი აღწერილი გზით.

შესატანი მონაცემები: პირველ სტრიქონში ორი მთელი რიცხვი – n და m;

გამოსატანი მონაცემები: ერთი მთელი რიცხვი – მიღებული კვადრატების რაოდენობა.

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი 3 7 5

9999 9999 1

განმარტება. პირველ მაგალითში მიღებული კვადრატების ზომებია: 3,3,1,1,1.

ანალიზი. ცხადია, რომ 20000 გაჭრაზე მეტი არ დაგვჭირდება, ამიტომ საკმარისია

პროცესის სიმულაცია. გაჭრები გაგრძელდება ვიდრე N და M ტოლი არ გახდება. თუ N>M,

მოიჭრება M*M კვადრატი და დარჩება (N-M)*M მართკუთხედი, ხოლო თუ M>N, მოიჭრება N*N

კვადრატი და დარჩება N*(M-N) ზომის მართკუთხედი. გაჭრების რაოდენობას ავჯამავთ.

#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;

}

ამოცანა 50. მაღლები და დაბლები

(ბულგარეთის ეროვნული ოლიმპიადა, 2008-09 წელი, რეგიონული ტური, 4-5 კლასი)

მოცემულია დადებითი მთელი რიცხვებისაგან შედგენილი მიმდევრობა, რომელიც

წრიულადაა განლაგებული და პირველი წევრი ბოლო წევრის მეზობელია. რიცხვს ეწოდება

მაღალი, თუ იგი თავის ორივე მეზობელზე მეტია, ხოლო რიცხვს ეწოდება დაბალი, თუ იგი

თავის ორივე მეზობელზე ნაკლებია. დაწერეთ პროგრამა, რომელიც მოცემულ მიმდევრობაში

იპოვის მაღალი და დაბალი რიცხვების რაოდენობები.

შესატანი მონაცემები: თითო სტრიქონში მოცემულია თითო მთელი დადებითი რიცხვი.

მიმდევრობა მთავრდება რიცხვით 0, რომელიც არ წარმოადგენს მიმდევრობის წევრს.

გამოსატანი მონაცემები: ორი მთელი რიცხვი – მაღალი რიცხვების რაოდენობა და დაბალი

რიცხვების რაოდენობა.

შეზღუდვები: შემოსატანი რიცხვების რაოდენობა არანაკლებ 4-ია და თითოეული რიცხვი

არ აღემატება 1 000 000-ს.

Page 42: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

42

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი 4

3

7

2

0

2 2

7

4

2

1

0

1 1

ანალიზი. რიცხვების წრფივი განლაგების შემთხვევაში ამოცანა გამარტივდებოდა. მათი

წრიული განლაგების გამო კი საჭიროა პირველი და მეორე რიცხვების მნიშვნელობა რაიმე

ცვლადებში დავიმახსოვროთ და ძირითადი ციკლის დასრულების შემდეგ ცალკე განვიხილოთ

სამეულები: (ბოლოსწინა რიცხვი, ბოლო რიცხვი, პირველი რიცხვი) და (ბოლო რიცხვი,

პირველი რიცხვი, მეორე რიცხვი).

#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;

}

Page 43: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

43

ორმაგი ციკლი

ორმაგი ციკლი, ანუ ერთი ციკლის შიგნით მეორე ციკლის ჩადგმა ხშირად არის საჭირო

სხვადასხვა ტიპის ამოცანების ამოხსნისას. პირველ მათგანს გარე ციკლს უწოდებენ, ხოლო

მეორეს (ჩადგმულს) – შიგა ციკლს. ასეთი კონსტრუქციის გამოყენებას რაიმე პრინციპული

თავისებურება არ გააჩნია, მაგრამ გამოცდილების მიღებამდე არცთუ იშვიათად ხდება

შეცდომების მიზეზი, ამიტომ ღირს ამ საკითხზე ყურადღების გამახვილება. განვიხილოთ

ორმაგი ციკლის მარტივი კოდი: 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

ზოგადად რომ ვთქვათ, გარე ციკლის თითო ბიჯზე (იტერაციაზე) შიგა ციკლი მთლიანად

სრულდება. საბოლოოდ, გარე ციკლი მხოლოდ ერთხელ სრულდება, ხოლო შიგა ციკლი

იმდენჯერ სრულდება, რამდენჯერაც შეიცვლის მნიშვნელობას გარე ციკლის ცვლადი.

ყველაზე ხშირად შეცდომებამდე მივყავართ გარე და შიგა ციკლებში ერთ და იმავე

ციკლის ცვლადთა გამოყენებას.

ამოცანა 51. დახატეთ მართკუთხედი.

დაწერეთ პროგრამა, რომელიც მოცემული ორი მთელი A და B (1 < A, B < 20)

რიცხვისათვის “*” სიმბოლოს საშუალებით გამოიტანს A სიმაღლის და B სიგანის

მართკუთხედს.

შესატანი მონაცემები: ჰარით გაყოფილი ორი მთელი რიცხვი – A და B.

გამოსატანი მონაცემები: შესაბამისი მართკუთხედის გამოსახულება.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი

2 4 ****

****

ანალიზი. B ცალი სიმბოლოს ერთ ხაზზე დაბეჭდვა for ციკლით სირთულეს არ

წარმოადგენს და ის უნდა განხორციელდეს შიგა ციკლში. გარე ციკლმა შიგა ციკლი უნდა

გაიმეოროს A–ჯერ და ამასთან, შიგა ციკლის დასრულების შემდეგ უნდა უზრუნველყოს ახალ

სტრიქონზე გადასვლა, წინააღმდეგ შემთხვევაში ყველა სიმბოლო ერთ სტრიქონში დაიბეჭდება.

#include <iostream>

int A,B;

main() {

cin>>A>> B; for (i = 1; i <= A; i++){

for ( j = 1; j <= B; j++) {

cout<<”*”; }

cout<<endl; }

}

Page 44: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

44

ამოცანა 52. დახატეთ მართკუთხა სამკუთხედი.

დაწერეთ პროგრამა, რომელიც მოცემული მთელი N (1 < N < 20) რიცხვისათვის “*”

სიმბოლოს საშუალებით გამოიტანს N კათეტის მქონე ტოლფერდა მართკუთხა სამკუთხედს.

შესატანი მონაცემები: ერთი მთელი რიცხვი – N.

გამოსატანი მონაცემები: შესაბამისი მართკუთხა სამკუთხედის გამოსახულება.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი

5 *

**

***

****

*****

ანალიზი. ეს ამოცანა ძალიან წააგავს წინა ამოცანას და ფაქტობრივად, იგივე კოდია

საჭირო. განსხვავება მხოლოდ ისაა, რომ შიგა ციკლი იცვლება არა რაღაც ფიქსირებულ

რიცხვამდე, არამედ გარე ციკლის ცვლადის სიდიდემდე, რომელიც ყოველ იტერაციაზე 1–ით

იზრდება.

#include <iostream>

int A;

main() {

cin>>A; for (i = 1; i <= A; i++){

for ( j = 1; j <= i; j++) {

cout<<”*”; }

cout<<endl; }

}

ამოცანა 53. ხორვატული საჭადრაკო დაფა

(ხორვატიის ღია პირველობა, 2012-13 წელი, მე-3 შეჯიბრი)

მირკო პატრიოტია და სურს, რომ თქვენ დაწეროთ პროგრამა, რომელიც

ხორვატულ საჭადრაკო დაფას დახატავს. დაფა შეიცავს წითელ და თეთრ უჯრებს. ზედა

მარცხენა უჯრა ყოველთვის წითელია. წითელი და თეთრი უჯრები მონაცვლეობენ

როგორც სვეტში, ასევე სტრიქონში. დაფა შედგება R×C უჯრისაგან, ხოლო თითოეული

უჯრა შედგება A*B სიმბოლოსაგან. წითელი უჯრები შედგება მაღალი რეგისტრის ‘X’

სიმბოლოსაგან, ხოლო თეთრი უჯრები ‘.’ (წერტილი) სიმბოლოსაგან. ყურადღებით

გაარჩიეთ ამოცანაში მითითებული მაგალითები.

შესატანი მონაცემები: პირველ სტრიქონში ორი მთელი რიცხვი – R და C (1≤ R,C≤10).

მეორე სტრიქონში ორი მთელი რიცხვი – A და B (1≤A,B≤ 10) გამოსატანი მონაცემები: გამოიტანეთ R*A სტრიქონი და C*B სვეტი, რომლებსაც ექნებათ

ზემოთ აღწერილი დაფის ფორმა.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 2 4

2 2

XX..XX..

XX..XX..

..XX..XX

..XX..XX 5 5

2 3

XXX...XXX...XXX

XXX...XXX...XXX

Page 45: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

45

...XXX...XXX...

...XXX...XXX...

XXX...XXX...XXX

XXX...XXX...XXX

...XXX...XXX...

...XXX...XXX...

XXX...XXX...XXX

XXX...XXX...XXX

ანალიზი. ჭადრაკის დაფის წითელი უჯრების ინდექსების ჯამი ყოველთვის ლუწია,

ხოლო თეთრი უჯრების ინდექსების ჯამი - ყოველთვის კენტი. გამოვიყენოთ ეს თვისება და

ორმაგ ციკლში ყოველ ბიჯზე გამოვთვალოთ ესა თუ ის პოზიცია ინდექსთა კენტი ჯამის მქონე

უჯრებს ეკუთვნის, თუ - ლუწი ჯამის.

#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;

}

}

ამოცანა 54. დომინო

ხორვატიის ღია პირველობა ინფორმატიკაში (2009/10 წელი, შეჯიბრი 1)

დომინო მოზაიკური რიცხვითი თამაშია. დომინოს ყოველი ქვა გაყოფილია ორ ნაწილად

და თითოეულ ნაწილზე დატანილია გარკვეული რიცხვის შესაბამისი წერტილები (შესაძლოა

ნულის შესაბამისიც, ანუ არცერთი). წერტილების რაოდენობა დამოკიდებულია კრებულის

ზომაზე. N ზომის დომინოს კრებული შეიცავს წერტილებს 0–დან N–მდე ჩათვლით. დომინოს

ქვის ნაწილები გადანომრილი არ არის და თუ ორი ქვა შეიცავს წერტილების ტოლ რაოდენობას

სხვადასხვა მიმდევრობით, ეს ქვები იდენტურად ითვლება. მაგალითად, ქვა წერტილების

რაოდენობით 2 და 8, ითვლება ისეთი ქვის იდენტურად, რომელზეც წერტილების რაოდენობაა

8 და 2. ცნობილია, რომ N ზომის დომინოს სრული კრებული შეიცავს ნაწილების ყველა

შესაძლო კომბინაციას N–ზე ნაკლები ან ტოლი წერტილებისათვის და არ შეიცავს იდენტურ

ქვებს. მაგალითად, 2 ზომის დომინოს კრებული შეიცავს 6 ქვას:

დაწერეთ პროგრამა, რომელიც გამოითვლის წერტილების საერთო ჯამს N ზომის

დომინოს სრული კრებულისათვის.

შესატანი მონაცემები: ერთი მთელი რიცხვი – N (1<= N<=1000).

გამოსატანი მონაცემები: ერთი მთელი რიცხვი – წერტილების საერთო ჯამი N ზომის

დომინოს სრული კრებულისათვის.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი

Page 46: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

46

2 12

3 30

15 2040

განმარტება. მეორე მაგალითისათვის: 3 ზომის დომინოს კრებული შეიცავს ქვებს: [0|0],

[0|1], [0|2], [0|3], [1|1], [1|2], [1|3], [2|2], [2|3] და [3|3].

ანალიზი. ამ ამოცანის ამოხსნა წააგავს მართკუთხა სამკუთხედის დახატვის ამოცანას.

დომინოს ყველა ქვის გენერაციისათვის საჭიროა შიგა ციკლის ცვლადი გარე ციკლის ცვლადის

მნიშვნელობამდე ვცვალოთ. ეს თავიდან აგვაცილებს იდენტური ქვების მიღებას. ყურადღება

მიაქციეთ იმას, რომ არც გარე და არც შიგა ციკლს ფიგურული ფრჩხილები არ აქვს. ამ

შემთხვევაში ციკლების მიერ სრულდება მხოლოდ ერთადერთი სტრიქონი, რომელიც

უშუალოდ მოსდევს შიგა ციკლის სტრიქონს.

#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);

}

ამოცანა 55. ვახშამი ხუთისათვის

ხორვატიის ღია პირველობა ინფორმატიკაში (2008/09 წელი, შეჯიბრი 3)

პოპულარულ შოუში „ვახშამი ხუთისათვის“ ხუთი მონაწილე ეჯიბრება ერთმანეთს

კულინარიულ ხელოვნებაში. ყოველ საღამოს ერთ–ერთი მათგანი ამზადებს ვახშამს, ხოლო

დანარჩენი ოთხიდან თითოეული აფასებს მას ქულით 1–დან 5–მდე. მონაწილის საბოლოო

შედეგი წარმოადგენს მიღებული ქულების ჯამს. შოუში გამარჯვებულად ითვლება ის

მონაწილე, რომელიც ყველაზე მეტ ქულას მოაგროვებს.

დაწერეთ პროგრამა, რომელიც გაარკვევს შოუს გამარჯვებულს და მის მიერ დაგროვებულ

ქულებს.

შესატანი მონაცემები: ხუთი სტრიქონიდან თითოეულში მოცემულია ოთხ–ოთხი მთელი

რიცხვი. მონაწილეები გადანომრილი არიან 1–დან 5–მდე და თითოეულის ნომერი ემთხვევა

სტრიქონის ნომერს. პასუხის ერთადერთობა გარანტირებულია.

გამოსატანი მონაცემები: ჰარით გაყოფილი ორი მთელი რიცხვი: გამარჯვებული

მონაწილის ნომერი და მის მიერ მოგროვებული ქულების ჯამი.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 5 4 4 5

5 4 4 4

5 5 4 4

5 5 5 4

4 4 4 5

4 19

4 4 3 3

5 4 3 5

5 5 2 4

5 5 5 1

4 4 4 4

2 17

Page 47: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

47

ანალიზი. ორმაგი ციკლის გარე ციკლში ვცვალოთ მონაწილეთა ნომრები, ხოლო შიგა

ციკლში გამოვთვალოთ შესაბამისი მონაწილის ქულათა ჯამი. შიგა ციკლის დასრულების

შემდეგ ორ ცვლადში დავიმახსოვროთ საუკეთესო შედეგი და მისი შესაბამისი ნომერი.

#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;

}

ამოცანა 56. ფიფქია და შვიდი ჯუჯა

ხორვატიის ღია პირველობა ინფორმატიკაში (2006/07 წელი, შეჯიბრი 3)

ყოველდღიურად, როდესაც ჯუჯები მაღაროში მუშაობენ, ფიფქია მათთვის ვახშამს

ამზადებს: 7 სკამი, 7 თეფში, 7 ჩანგალი და 7 დანა 7 მშიერი ჯუჯისათვის.

ერთ მშვენიერ დღეს მაღაროდან შვიდი ჯუჯის ნაცვლად ცხრა დაბრუნდა (დღესაც კი

არავინ იცის, როგორ ან რატომ). ცხრავე მათგანი თავგამოდებით ამტკიცებდა, რომ სწორედ ის

იყო ფიფქიას შვიდი ჯუჯიდან ერთ–ერთი.

საბედნიეროდ, ყოველ ჯუჯას ქუდზე აწერია მთელი დადებითი რიცხვი 1–დან 100–მდე.

ფიფქიამ კი, როგორც ეს ცნობილ მათემატიკოსს შეეფერება, იცის, რომ მისი ჯუჯების ქუდებზე

აღნიშნულ რიცხვთა ჯამი ზუსტად 100–ს შეადგენს.

დაწერეთ პროგრამა, რომელიც დაადგენს ფიფქიას 7 ჯუჯის ვინაობას, ანუ ცხრიდან იმ

შვიდ რიცხვს, რომელთა ჯამი 100–ის ტოლია.

შესატანი მონაცემები: ცხრა მთელი რიცხვი, რომელთაგან თითოეული მოთავსებულია

დიაპაზონში 1–დან 99–მდე (ჩათვლით). ყველა რიცხვი განსხვავებულია.

შენიშვნა: შესატანი მონაცემები უზრუნველყოფენ პასუხის ერთადერთობას.

გამოსატანი მონაცემები: ზუსტად შვიდი მთელი რიცხვი – ფიფქიას 7 ჯუჯის ქუდებზე

აღნიშნული ნომრები. რიცხვები გამოიტანეთ ნებისმიერი მიმდევრობით.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 7 8 10 13 15 19 20 23 25 7 8 10 13 19 20 23 8 6 5 1 37 30 28 22 36 8 6 5 1 30 28 22

ანალიზი. თუკი ვეცდებით იმ 7–7 რიცხვის გადარჩევას, რომელთა ჯამიც 100–ს იძლევა,

მაშინ დაგვჭირდება შვიდმაგი ჩადგმული ციკლი. გაცილებით მარტივი იქნება დავადგინოთ

ცხრავე რიცხვის ჯამი და ვცადოთ იმ 2–2 რიცხვის გადარჩევა, რომელთა გამოკლებითაც

მიღებულ ჯამზე, 100–ს მივიღებთ. ამის ორგანიზება ორმაგი ციკლითაც შეიძლება.

Page 48: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

48

#include <cstdio>

int main() {

int broj[9], suma = 0;

for( int i = 0; i < 9; ++i ) {

scanf( "%d", &broj[i] );

suma += broj[i];

}

for( int i = 0; i < 9; ++i )

for( int j = i+1; j < 9; ++j )

if( suma - broj[i] - broj[j] == 100 )

for( int k = 0; k < 9; ++k )

if( k != i && k != j )

printf( "%d\n", broj[k] );

}

ამოცანა 57. ორი ამოცანა http://codeforces.com/problemset/problem/203/A

პატარა ვალერი Codeforces–ის საიტზე დარეგისტრირდა Valera–ს ნიკით და პირველ

შეჯიბრშიც მიიღო მონაწილეობა. მან დაწერა რაუნდი #300 და დაიტრაბახა თავის მეგობარ

არკადისთან, რომ პირველივე შეჯიბრში x ქულა მოაგროვა. არკადიმ მას არ დაუჯერა და

გადაწყვიტა შეემოწმებინა ვალერის შედეგი. მან იცოდა, რომ რაუნდი #300 განსხვავებული

ფორმატით ჩატარდა და სულ 2 ამოცანა იყო ამოსახსნელი. შეჯიბრი გრძელდებოდა t წუთი,

ხოლო წუთები გადანომრილი იყო 0–დან. პირველი ამოცანის საწყისი ფასი იყო a ქულა, ხოლო

ყოველი წუთის გასვლის შემდეგ მისი ფასი მცირდებოდა da ქულით. მეორე ამოცანის საწყისი

ფასი იყო b ქულა და ყოველი წუთის გასვლის შემდეგ მისი ფასი მცირდებოდა db ქულით.

ამრიგად, როცა შეჯიბრის ნულოვანი წუთი დამთავრდება, პირველი ამოცანის ფასი იქნება a-da

ქულა, ხოლო მეორე ამოცანის ფასი – b-db ქულა. გარანტირებულია, რომ ამოცანის ფასი

ყოველთვის არაუარყოფითი იქნება.

არკადი გთხოვთ თქვენ დაადგინოთ, შეეძლო თუ არა ვალერის აეღო შეჯიბრზე ზუსტად x

ქულა. ჩათვალეთ, რომ ვალერის არცერთ ამოცანაზე არ დაუხარჯავს 1 ცდაზე მეტი. ამასთან,

ორივე ამოცანისთვის ამოხსნის გაგზავნა მას შეეძლო ერთსა და იმავე წუთს, დაწყებული

ნულოვანი წუთიდან და დამთავრებული t-1 წუთით. მიაქციეთ ყურადღება, რომ ამოცანის

გაგზავნა შეჯიბრის დაწყებიდან ზუსტად t წუთის შემდეგ შეუძლებელია.

შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია ექვსი მთელი რიცხვი, x, t, a, b,

da, db (0≤x≤600; 1≤ t, a, b, da, db≤300) – ვალერის შედეგი, შეჯიბრის ხანგრძლივობა, პირველი

ამოცანის საწყისი ფასი, მეორე ამოცანის საწყისი ფასი, ქულების რაოდენობა, რომლითაც

მცირდება შესაბამისად პირველი და მეორე ამოცანების ფასები ყოველი წუთის შემდეგ.

გამოსატანი მონაცემები: თუ ვალერის შეეძლო შეჯიბრში ზუსტად x ქულის მოგროვება,

გამოიტანეთ YES, წინააღმდეგ შემთხვევაში – NO.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 30 5 20 20 3 5 YES 10 4 100 5 5 1 NO

განმარტება. პირველ მაგალითში ქულების მოგროვება ასე შეიძლებოდა: პირველი ამოცანა

უნდა ჩაბარებულიყო 0 წუთზე, მეორე კი – მეორე წუთზე. მაშინ პირველ ამოცანაში ვალერი

მიიღებდა 20 ქულას, მეორეში კი – 10–ს, რაც ჯამში 30 ქულას წარმოადგენს.

ანალიზი. ორმაგი ციკლის საშუალებით გადავარჩიოთ ქულების ყველა შესაძლო ჯამი.

Page 49: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

49

#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).

გამოსატანი მონაცემები: შესაბამისი მართკუთხა სამკუთხედის გამოსახულება.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი

20 1

ანალიზი. ორმაგი ციკლის საშუალებით გადავარჩიოთ ყველა შესაძლო კვადრატების ჯამი.

#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;

}

ამოცანა 59. შუქნიშნები

ხორვატიის ღია პირველობა ინფორმატიკაში (2007/08 წელი, შეჯიბრი 6)

ლუკა სატვირთო მანქანით მოძრაობს გრძელ სწორ გზატკეცილზე, რომლის გასწვრივაც

ბევრი შუქნიშანია განლაგებული. თითოეული შუქნიშნისათვის მან იცის, რამდენ ხანს იქნება

ანთებული წითელი და მწვანე შუქი (ეს ორი ფერი შუქნიშნებზე უსასრულოდ მონაცვლეობს).

ლუკას მიერ მოძრაობის დაწყების მომენტში, ყველა შუქნიშანზე წითელი ფერი ერთდროულად

იწყებს საკუთარ ციკლს. სატვირთო მანქანა მანძილის ერთეულს 1 წამში. ის შუქნიშანთან

ჩერდება წითელი ფერის შემთხვევაში და მწვანე ფერის ანთებისთანავე აგრძელებს მოძრაობას.

დაწერეთ პროგრამა, რომელიც გაარკვევს, თუ რამდენ ხანში მიაღწევს ლუკა გზატკეცილის

ბოლოს. დისტანციის საწყისი წერტილი არის 0, ხოლო საბოლოო – L.

შესატანი მონაცემები: პირველ სტრიქონში მოცემულია ორი მთელი რიცხვი N და L (1 ≤ N

≤ 100, 1 ≤ L ≤ 1000), შესაბამისად შუქნიშნების რაოდენობა და დისტანციის სიგრძე.

მომდევნო N სტრიქონიდან თითოეულში მოცემულია სამ–სამი მთელი რიცხვი D, R და G,

რომლებიც აღწერენ თითო შუქნიშანს (1 ≤ D < L, 1≤ R ≤ 100, 1 ≤ G ≤ 100). D არის მანძილი გზის

საწყისი წერტილიდან შესაბამის შუქნიშნამდე, ხოლო R და G არიან ამ შუქნიშანზე წითელი და

მწვანე ფერების ნათების ხანგრძლივობა. შუქნიშნების აღწერა მოცემულია D მონაცემის

ზრდადობის მიხედვით, რომელიც შუქნიშანთა არცერთ წყვილს არ აქვს ერთნაირი.

Page 50: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

50

გამოსატანი მონაცემები: ერთი მთელი რიცხვი – დრო (წამებში), რომელიც დასჭირდება

ლუკას დისტანციის ბოლომდე მისასვლელად.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 2 10

3 5 5

5 2 2

12

4 30

7 13 5

14 4 4

15 3 10

25 1 1

36

განმარტება. პირველ მაგალითში ლუკა 2 წამით შეჩერდება პირველ შუქნიშანთან, ხოლო

მეორესთან მისვლის დროს მწვანე შუქი იქნება ანთებული და მას შეჩერების გარეშე გაივლის.

ანალიზი. პროცესის სიმულაციისათვის გამოვიყენოთ ორმაგი ციკლი. გარე for ციკლის

საშუალებით აღვწეროთ გადაადგილებები შუქნიშნებს შორის, ხოლო შიგა while ციკლმა

გამოთვალოს თითოეულ შუქნიშანთან დგომის დრო. #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;

}

ამოცანა 60. ჩლიქოსნური გადამრავლება – Cow Multiplication [Jeffrey Wang]

USACO, 2007/08 წლის თებერვლის შეჯიბრი, “ბრინჯაოს” დივიზიონი ბესის მოჰბეზრდა რიცხვთა წყვილების გადამრავლების ჩვეულებრივი მეთოდი და

გადაწყვიტა საკუთარი მეთოდი შემოიღოს. მისი მეთოდის მიხედვით, A*B გამოსახულება

ტოლია A და B რიცხვების შემადგენელი ციფრების წყვილთა ყველა შესაძლო კომბინაციის

ნამრავლთა ჯამისა. მაგალითად, გამოსახულება 123*45 ტოლი იქნება 1*4+1*5+2*4+2*5+3*4+3*5=54.

მოცემული ორი მთელი A და B (1<=A,B<=1,000,000,000)რიცხვისათვის განსაზღვრეთ რისი

ტოლი იქნება A*B ბესის მეთოდით.

შესატანი მონაცემები: ჰარით გაყოფილი ორი მთელი რიცხვი: A და B.

გამოსატანი მონაცემები: ერთადერთ სტრიქონში გამოტანილ უნდა იქნას A*B ნამრავლი

ბესის მეთოდით.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 123 45 54

Page 51: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

51

ანალიზი. ორმაგი ციკლის გარე ციკლში მოვახდინოთ პირველი რიცხვის ციფრების

გენერაცია, ხოლო შიგა ციკლში მეორე რიცხვის ციფრები მივიღოთ. მიაქციეთ ყურადღება 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;

}

Page 52: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

52

ოპერატორები continue, break, goto, return

ამ ოპერატორებს ზოგადად გადასვლის ოპერატორებსაც უწოდებენ. ინსტრუქციები

continue და break გამოიყენებიან მხოლოდ ციკლის (როგორც for–ის, ისე while–ის)

შიგნით. break–ი გამოიყენება switch ოპერატორშიც. ყველა სხვა შემთხვევაში მათი

გამოყენება იწვევს შეცდომის შეტყობინებას.

ოპერატორი continue იწვევს პროგრამის გადასვლას ციკლის ბოლოზე, ხოლო მისი

მომდევნო ყველა ბრძანება ციკლის ბოლომდე გამოიტოვება. ამის შემდეგ სრულდება ციკლის

მომდევნო იტერაცია. ოპერატორი break იწვევს ციკლის შეწყვეტას და პროგრამა გადადის

ციკლის შემდეგ არსებულ პირველივე ოპერატორზე. continue–ც და break–ც, როგორც წესი,

გამოიყენებიან შედარების ოპერატორის დახმარებით, რადგან მათი უპირობო გამოყენება

ზედმეტს გახდიდა ყველა ბრძანებას, რომლებიც მათ შემდეგ წერია ციკლის ბოლომდე.

მაგალითისთვის განვიხილოთ პროგრამის ფრაგმენტი, რომელიც ამოწმებს პაროლის

სისწორეს და მხოლოდ სწორი პაროლის შემთხვევაში იწყებს მუშაობას. სიმარტივისათვის

სწორი პაროლი კოდშივე ჩავდოთ და რაიმე ცვლადს (ვთქვათ, pass_value) მივანიჭოთ. x=1; pass_value=135246;

while(x>0) {

printf("შეიტანეთ პაროლი: "); scanf("%d",&password);

if (pass_value!=password) continue; else break;

}

y=37;

...

პაროლის არასწორად აკრების შემთხვევაში პროგრამა გადავა ციკლის ბოლო

ოპერატორზე, რის შემდეგაც ციკლი თავიდან დაიწყება და ხელახლა მოითხოვს პაროლს.

პაროლის სწორად მითითების შემთხვევაში პროგრამა გამოვა ციკლიდან და გადავა

ოპერატორზე y=37;

ოპერატორი goto პროგრამირების ადრეულ ეტაპებზე ყველა ენაში მნიშვნელოვან როლს

თამაშობდა. პროგრამული ენების განვითარებასთან ერთად მან თანდათან დაჰკარგა

პოპულარობა და დღეს ითვლება, რომ პროგრამის სწორად შედგენის შემთხვევაში goto–ს

გამოყენება არასდროს არაა საჭირო. ამ ოპერატორის გამოყენებისას აუცილებელია ე.წ. „ჭდე“,

რომელიც წარმოადგენს იდენტიფიკატორს ორწერტილით. მაგალითისათვის განვიხილოთ

კოდი, სადაც goto–ს საშუალებით ორგანიზდება ციკლი: x = 9;

label24: x++;

if(x<=100) goto label24;

ერთადერთი სიტუაცია, როდესაც goto–ს გამოყენება ეფექტურად შეიძლება ჩავთვალოთ,

ესაა გამოსვლა ერთბაშად რამდენიმე ჩადგმული ციკლიდან, რასაც break–ი ვერ ახერხებს.

ოპერატორი return გამოიყენება ფუნქციიდან გამოსასვლელად. მისი ზოგადი ფორმაა:

return გამოსახულება;

მისი შესაძლებლობა ფუნქციიდან მნიშვნელობის დაბრუნების დროს განხილული იქნება

თავში „ფუნქციები“. აქ კი აღვნიშნოთ რომ ბრძანება return 0; პროგრამის ნებისმიერ ადგილას

იწვევს პროგრამის მუშაობის შეწყვეტას.

Page 53: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

53

ამოცანა 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;}

}

ამოცანა 62. მარტივი რიცხვები

(ბულგარეთი, ზამთრის შეჯიბრი ინფორმატიკაში, 4–5 კლასი, 2010)

ივანჩომ ფურცელზე ჩამოწერა ყველა მარტივი რიცხვი, რომელი მეტია A–ზე და ნაკლებია

B–ზე. დაწერეთ პროგრამა, რომელიც დაადგენს, რამდენი ციფრი დაწერა ივანჩომ.

შესატანი მონაცემები: ორი მთელი რიცხვი A и B (1<A<B<100000).

გამოსატანი მონაცემები: ერთი მთელი რიცხვი – ციფრთა შესაბამისი რაოდენობა.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი

2 20 11

ანალიზი. დავწეროთ for ციკლი A–დან B–მდე და ყოველი რიცხვი შევამოწმოთ

მარტივობაზე (პროგრამაში დასკვნა ამის შესახებ კეთდება s ცვლადის საშუალებით) #include<iostream>

using namespace std;

int a, b, s, p, sum=0;

int main(){

cin >> a >> b;

for(int i=a+1; i<b; i++)

{ s=0;

for(int d=2; d*d<=i; d++)

if(i%d==0) {s=1; break;}

if(s == 0)

{ p=i;

while(p!=0)

{ sum++;

p=p/10;

}

}

}

cout << sum << endl;

}

Page 54: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

54

ამოცანა 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

u

f

u

d

f

3

განმარტება: მაგალითში ბესის აქვს 13 წამი შინ დასაბრუნებლად, ხოლო მთლიანი გზა

შედგება 5 სეგმენტისაგან. აღმართის გასარბენად ხარჯავს 3 წამს, ვაკეზე - 2 წამს და დაღმართზე

- 1 წამს. გზა ვიზუალურად ასე გამოიყურება: _/\_

/

ბესის შეუძლია გაირბინოს სამი სეგმენტი და დაბრუნდეს უკან 3+2+3+1+2+1 = 12 წამში, რაც

ერთი წამით ნაკლებია დროის ლიმიტზე. თუკი ბესი მოინდომებს მომდევნო სეგმენტის

გარბენასაც, მაშინ უკან დროულად დაბრუნებას ვეღარ მოასწრებს.

ანალიზი. ერთი შეხედვით ამოცანაში 3 განსხვავებული ტიპის სეგმენტი გვაქვს

განსახილველი. სინამდვილეში აღმართი და დაღმართი ერთნაირი ხასიათის სეგმენტებია,

რადგან უკან დაბრუნებისას აღმართი დაღმართად გადაიქცევა და დაღმართი – აღმართად. ამის

გამო, თითოეული ასეთი სეგმენტის გავლას ორივე მიმართულებით სჭირდება U+D დრო, ხოლო

„ვაკე“ ტიპის სეგმენტის გავლას – 2*F დრო.

Page 55: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

55

#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;

}

ამოცანა 64. კამათლის კოშკი

http://codeforces.com/problemset/problem/225/A

კამათელი წარმოადგენს კუბს, რომლის წახნაგებზე შავი წერტილების სახით

გამოსახულია სხვადასხვა მთელი რიცხვები 1–დან 6–მდე. ამასთან, მოპირდაპირე წახნაგებზე

გამოსახულ რიცხვთა ჯამი ყოველთვის 7–ის ტოლია. შევნიშნოთ, რომ მოცემულ შეზღუდვებს

აკმაყოფილებს სულ ორნაირი კამათელი, რომლებიც ერთმანეთის სარკულ ასახვას (ნახაზი

მარცხნივ).

ალისა და ბობი თამაშობენ კამათლებით. ალისამ ააშენა კოშკი n კამათლისაგან. ცნობილია,

რომ ამ კოშკში კამათლები ერთმანეთს განსხვავებული რიცხვების მქონე წახნაგებით ეხებიან.

ბობს სურს, რომ ცალსახად განსაზღვროს კამათლის წახნაგებზე აღნიშნული რიცხვების

მნიშვენელობები. სამწუხაროდ, ბობი კოშკს მხოლოდ ერთი მხრიდან აკვირდება, ამიტომ ყველა

რიცხვს ვერ ხედავს წახნაგებზე. ბობი ხედავს კოშკის წვეროზე მდებარე კამათლის ზედა

წახნაგს, ასევე – ორ–ორ რიცხვს კოშკის ნებისმიერი კამათლის მეზობელ წახნაგებზე (ნახაზი

მარჯვნივ).

დაეხმარეთ ბობს გაარკვიოს, შესაძლებელია თუ არა მის ხელთ არსებული ინფორმაციით

ცალსახად განისაზღვროს რიცხვები კოშკში მოთავსებული კამათლების ყველა წახნაგზე.

შესატანი მონაცემები: პირველ სტრიქონში ერთი მთელი რიცხვი: n (1≤n≤100) –

კამათლების რაოდენობა კოშკში. მეორე სტრიქონში ერთი მთელი რიცხვი x (1≤x≤6) — რიცხვი,

რომელსაც ხედავს ბობი კოშკის წვეოზე. მომდევნო n სტრიქონიდან თითოეულში: ორ–ორი

მთელი რიცხვი ai, bi (1≤ai,bi≤6; ai≠bi) — რიცხვები, რომლებსაც ბობი ხედავს i-ური კამათლის

გვერდით წახნაგებზე. ჩათვალეთ, რომ კამათლები კოშკში გადანომრილია ზემოდან ქვემოთ 1–

დან n–მდე. გარანტირებულია, რომ შესატან მონაცემებში მითითებული სახით კოშკის აგება

შესაძლებელია.

გამოსატანი მონაცემები: გამოიტანეთ სიტყვა „YES“, თუკი კოშკში მდებარე

კამათლების ყველა წახნაგზე არსებული რიცხვების განსაზღვრა ცალსახად არის

შესაძლებელი. წინააღდეგ შემთხვევაში გამოიტანეთ „NO“.

Page 56: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

56

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 3

6

3 2

5 4

2 4

YES

3

3

2 6

4 1

5 3

NO

ანალიზი. რადგან სრული ინფორმაცია მხოლოდ ყველაზე ზედა კამათელზე გვაქვს,

განხილვა სწორედ მისგან უნდა დავიწყოთ და თანმიმდევრულად განვიხილოთ ყველა

კამათელი ზემოდან ქვემოთ. თუკი ჩვენს მიერ განსახილველი კამათლის ზედა ან ქვედა წახნაგი

ემთხვევა მისი მომდევნო კამათლის მარცხენა ან მარჯვენა წახნაგს, მაშინ ამ უკანასკნელის

შესახებ სრული ინფორმაციის ცალსახად მიღება შეუძლებელია. ამიტომ განხილვის პროცესი

შეგვიძლია შევწყვიტოთ და დავბეჭდოთ პასუხი.

#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;

}

ამოცანა 65. ფესვის ამოღება [Kolstad, 2005]

USACO, 2005 წლის დეკემბრის შეჯიბრი, “ბრინჯაოს” დივიზიონი

ძროხები სწავლობენ ფესვის ამოღებას, თუმცა ამას ადამიანებივით მოხერხებულად ვერ

აკეთებენ და გამუდმებით ეკარგებათ მთელი ნაწილი ფესვის ამოღების შემდეგ. მაგალითად, 2–

დან ფესვის ამოღებისას 1.4142135623730950488016887242096980785696–ის ნაცვლად

ღებულობენ 0.4142135623730950488016887242096980785696–ს, ხოლო 16–დან ფესვის

ამოღებისას 0–ს ღებულობენ.

ამოფესვის შეცდომები აშკარაა, მაგრამ ასეთ მიდგომას საინტერესო საკითხამდე

მივყავართ. თუკი მოცემულია L (1 <= L <= 9)სიგრძის ციფრთა მიმდევრობა, რა იქნება

უმცირესი რიცხვი, რომლის ფესვიც დაიწყება ამ მიმდევრობიდან?

მაგალითისათვის განვიხილოთ სტრიქონი „123“. ფესვი 17–დან მიახლოებით ტოლია

4.1231056256176605498214098559740770251472–ს. ძროხების მიერ შესრულებული

ამოფესვით მიიღება 0.1231056256176605498214098559740770251472. რიცხვის

ათწილადი ნაწილი იწყება „123“–ით, ხოლო 17 უმცირესია იმ რიცხვებს შორის, რომლებსაც ეს

თვისება გააჩნიათ.

შესატანი მონაცემები: პირველ სტრიქონში ერთი მთელი რიცხვი: L. მეორე სტრიქონში L

ცალი ციფრი ჰარების გარეშე.

გამოსატანი მონაცემები: ერთი მთელი რიცხვი - ყველაზე მცირე რიცხვი, რომლის

კვადრატული ფესვის ათწილადი ნაწილი იწყება ციფრთა მოცემული მიმდევრობით.

Page 57: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

57

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 3

123 17

ანალიზი. რაიმე სპეციალური ალგორითმი, რომლითაც პირდაპირ ვიპოვიდით პასუხს –

არ არსებობს. პასუხი უნდა გადავარჩიოთ 1–დან მილიარდის ფესვამდე და თუკი პასუხს

ვიპოვით, მაშინვე გამოვიტანოთ ის და შევწყვიტოთ პროგრამის შესრულება (კოდში ამას

ასრულებს ბრძანება exit). პასუხის შემოწმებისას უმჯობესია შევადაროთ რიცხვები და არა

სიმბოლოები, რადგან სიმბოლოების შემოწმება დიდ დროს საჭიროებს.

#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;

}

ამოცანა 66. Т-მარტივი რიცხვები

http://codeforces.com/problemset/problem/230/B

ცნობილია, რომ მარტივი ეწოდებათ ისეთ მთელ დადებით რიცხვებს, რომლებსაც

გააჩნიათ ზუსტად ორი განსხვავებული დადებითი გამყოფი. ამ განსაზღვრების ანალოგიით

მთელ დადებით რიცხვს დავარქვათ Т-მარტივი, თუკი მას გააჩნია ზუსტად სამი განსხვავებული

დადებითი გამყოფი.

თქვენ გეძლევათ მასივი, რომელიც შედგება n ცალი მთელი დადებითი რიცხვისაგან.

თითოეული მათგანისათვის დაადგინეთ Т-მარტივია ეს რიცხვი თუ არა.

შესატანი მონაცემები: პირველ სტრიქონში ერთი მთელი რიცხვი n (1≤n≤105) - რიცხვების

რაოდენობა მასივში. მეორე სტრიქონში ჰარით გაყოფილი n ცალი მთელი რიცხვი xi (1≤xi≤1012).

გამოსატანი მონაცემები: გამოიტანეთ n ცალი სტრიქონი. i-ური სტრიქონი უნდა

შეიცავდეს YES-ს, თუ რიცხვი xi არის Т-მარტივი და NO -ს, თუ რიცხვი xi არ არის Т-მარტივი.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 3

4 5 6

YES

NO

Page 58: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

58

NO

განმარტება. 4-ს გააჩნია ზუსტად 3 გამყოფი: 1, 2 და 4, ამიტომ ის Т-მარტივია. 5-ს ორი

გამყოფი აქვს (1 და 5), ხოლო 6-ს - ოთხი (1, 2, 3, 6).

ანალიზი. ზუსტად სამი გამყოფი შეიძლება ჰქონდეთ მხოლოდ მარტივი რიცხვის

კვადრატებს, ამიტომ თითოეული შემომავალი რიცხვიდან ამოვიღოთ ფესვი და შევამოწმოთ

არის თუ არა მიღებული შედეგი მთელი და მარტივი. #include<iostream>

#include<cmath>

using namespace std;

int main(){

int n,i,j;

long long a,b;

cin>>n;

for(i=1;i<=n;i++)

{

cin>>a;

b=sqrt(a);

for(j=2;j*j<=b;j++) if(b%j==0) break; if(j*j>b && b*b==a && a>1) cout<<"YES\n";

else cout<<"NO\n";

}

}

ამოცანა 67. თამაში ავტობუსში

http://codeforces.com/problemset/problem/79/A

მელა კეილი ავტობუსით მგზავრობისას შეხვდა კურდღელ ხანაკოს და მათ

გადაწყვიტეს შემდეგი თამაში ეთამაშათ:

• თამაშის დასაწყისში ისინი ერთ გროვაში ათავსებდნენ მონეტებს: 100 იენის

ღირებულების x ცალ მონეტას და 10 იენის ღირებულების y ცალ მონეტას.

• სვლებს რიგრიგობით აკეთებენ, თამაშს კი კეილი იწყებს.

• ყოველ სვლაზე მოთამაშემ უნდა აიღოს გროვიდან ზუსტად 220 იენი. თუკი

კეილის სვლაა და არსებობს 220 იენის ამორჩევის ერთზე მეტი ვარიანტი, მაშინ ის

ირჩევს ისეთ ვარიანტს, რომელშიც მეტია 100–იენიანი მონეტა. თუკი ხანაკოს სვლაა და

არსებობს 220 იენის ამორჩევის ერთზე მეტი ვარიანტი, მაშინ ის ირჩევს ისეთ ვარიანტს,

რომელშიც მეტია 10–იენიანი მონეტა.

• ის მოთამაშე, რომელიც ვერ ამოირჩევს ზუსტად 220 იენს – წაგებულია.

დაწერეთ პროგრამა, რომელიც გაარკვევს გამარჯვებულს მოცემული x–ისა და y–ის მიხედვით.

შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია ორი მთელი რიცხვი x (0 ≤ x ≤

106) და (0 ≤ y ≤ 106).

გამოსატანი მონაცემები: მელა კეილის გამარჯვების შემთხვევაში გამოიტანეთ „Ciel“,

წინააღმდეგ შემთხვევაში – „Hanako“.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 2 2 Ciel 3 22 Hanako

ანალიზი. მოვახდინოთ პროცესის სიმულაცია და ციკლის კენტ და ლუწ ბიჯებზე

გამოვთვალოთ აქვს თუ არა შესაბამის მოთამაშეს სვლის გაკეთების შესაძლებლობა.

Page 59: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

59

#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;

}

ამოცანა 68. ჯადოსნური რიცხვები

http://codeforces.com/problemset/problem/320/A

ჯადოსნურს უწოდებენ რიცხვს, რომელიც მიიღება 1, 14 და 144 რიცხვების

კონკატენაციით (გადაბმით). ამ სამი რიცხვიდან თითოეულის აღება შეგვიძლია

უსასრულოდ და ნებისმიერი თანმიმდევრობით. შესაბამისად, რიცხვები 14144, 141414

და 1411ჯადოსნურია, ხოლო რიცხვები 1444, 514 და 414 — არა.

თქვენ გეძლევათ რიცხვი. გაარკვიეთ, არის თუ არა ის ჯადოსნური.

შესატანი მონაცემები: ერთ სტრიქონში მოცემულია ერთი მთელი რიცხვი n (0 ≤ n ≤ 109).

გამოსატანი მონაცემები: გამოიტანეთ „YES“, თუკი n წარმოადგენს ჯადოსნურ რიცხვს,

წინააღმდეგ შემთხვევაში – „NO“.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 114114 YES 1111 YES 441231 NO

ანალიზი. შევამოწმოთ რიცხვის ბოლო ციფრები თუ უდრის 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");

}

Page 60: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

60

ამოცანა 69. რიგი კინოთეატრთან

http://codeforces.com/problemset/problem/349/ A

მართალია, ფილმი „კერკეტი კაკალი“ სულ ახალი გამოსულია, მაგრამ კინოთეატრის

სალაროებთან უკვე გაჩნდა n ადამიანისაგან შედგენილი უზარმაზარი რიგი. ყოველ მათგანს

ბილეთის შესაძენად აქვს თითო კუპიურა 100, 50 ან 25 რუბლის ღირებულებით. ბილეთი ღირს

25 რუბლი. შეძლებს თუ არა მოლარე, რომ რიგში მდგომ ყველა ადამიანს მიჰყიდოს ბილეთი და

დაუბრუნოს ხურდა, თუკ თავდაპირველად სალაროში ფული არ არის და მოლარე ბილეთებს

ჰყიდის მკაცრად რიგის მიხედვით?

შესატანი მონაცემები: პირველ სტრიქონში მოცემულია ერთი მთელი რიცხვი n (0 ≤n ≤ 105)

– ადამიანების რაოდენობა რიგში. მომდევნო სტრიქონში მოცემულია n ცალი მთელი რიცხვი,

რომელთაგან თითოეული 25-ის, 50-ის ან 100-ის ტოლია. რიცხვები თანმიმდევრობით

მოცემულია რიგის დასაწყისიდან (სალაროდან) რიგის დასასრულამდე.

გამოსატანი მონაცემები: გამოიტანეთ „YES“, თუკი მოლარე შეძლებს ყველა

ადამიანისათვის ბილეთის მიყიდვას და ხურდის დაბრუნებას. წინააღმდეგ შემთხვევაში

გამოიტანეთ „NO“.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 4

25 25 50 50 YES

2

25 100 NO

ანალიზი. შემოვიღოთ ორი მთვლელი 25-იანი და 50-იანი კუპიურებისათვის – a25 და a50.

კუპიურების რაოდენობის შესაბამისად სულ განსახილველია 3 შემთხვევა: ა) შემოდის 25. ამ

დროს ვზრდით a25-ს 1-ით. ბ) შემოდის 50. თუ 25-იანი კუპიურა არ გვაქვს, ვბეჭდავთ NO-ს და

ვასრულებთ პროგრამას, წინააღმდეგ შემთხვევაში ვამცირებთ a25-ს 1-ით. გ) შემოდის 100. ამ

შემთხვევაში ჯერ ვცდილობთ, რომ ხურდა დავაბრუნოთ 50-იანი და 25-იანი კუპიურებით

(შესაბამისად მათ მთვლელებს 1-ით ვამცირებთ), თუ ამის საშუალება არ არის, ვცდილობთ

ხურდა დავაბრუნოთ 3 ცალი 25-იანი კუპიურით და a25-ს ვამცირებთ 1-ით. თუ ესეც არ

ხერხდება, ვბეჭდავთ NO-ს და ვასრულებთ პროგრამას. კოდი დაწერილია goto ოპერატორის

გამოყენებით.

#include<iostream>

#include<stdio.h>

using namespace std;

int a25,a50,d,n,i;

main(){

cin>>n;

for(i=1;i<=n;i++){

cin>>d;

if(d==25) {a25++; goto lab1;}

if(d==50 && a25==0) goto lab2;

if(d==50 && a25>0) {a25--;a50++;goto lab1;}

if(d==100 && a25>=1 && a50>=1) {a25-=1;a50--;goto lab1;}

if(d==100 && a25>=3) a25-=3; else goto lab2;

lab1: ;

}

cout<<"YES";goto lab3;

lab2: cout<<"NO";

lab3: ;

}

Page 61: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

61

ამოცანა 70. გაქცევა

http://codeforces.com/problemset/problem/148/ B

პრინცესა აპირებს გაექცეს დრაკონს გამოქვაბულიდან და საჭიროა, რომ გაქცევა კარგად

დაიგეგმოს. პრინცესა დარბის vp მილი/საათში სიჩქარით, ხოლო დრაკონი დაფრინავს vd

მილი/საათში სიჩქარით. დრაკონი t საათის შემდეგ აუცილებლად შეამჩნევს პრინცესას გაქცევას

და დაუყოვნებლივ დაედევნება მას. პრინცესამ იცის, რომ დრაკონი მას უეჭველად დაეწევა,

მაგრამ მან შეამჩნია, რომ დრაკონს ძალიან ხარბია და არცთუ ძალიან ჭკვიანი. ამიტომ

პრინცესამ გადაწყვიტა, რომ გაქცევისას თან წაიღოს ზოგიერთი ძვირფასეულობა მისი

საგანძურიდან და როცა დრაკონი წამოეწევა, დააგდოს მიწაზე ერთ-ერთი მათგანი. დრაკონი

აიღებს ძვირფასეულობას და მაშინვე დაბრუნდება გამოქვაბულში მის შესანახად.

გამოქვაბულამდე მისასვლელად და ძვირფასეულობის შესანახად დრაკონს დასჭირდება f საათი, რის შემდეგაც ის ისევ გამოედევნება პრინცესას.

ჩავთვალოთ, რომ პრინცესაც და დრაკონიც მოძრაობენ წრფის გასწვრივ. რა რაოდენობის

ძვირფასეულობა უნდა წაიღოს პრინცესამ გამოქვაბულიდან, რომ მიაღწიოს საკუთარ

სასახლემდე. თუკი დრაკონი მას წამოეწევა უშუალოდ სასახლეში შესვლის მომენტში, ითვლება,

რომ პრინცესამ მოასწრო სასახლეში მისვლა და დამატებითი ძვირფასეულობა საჭირო არ არის.

შესატანი მონაცემები: ერთადერთ სტრიქონში შემოდის vp, vd, t, f და c (1≤vp,vd≤100,

1≤t,f≤10, 1≤c≤1000), გამოსატანი მონაცემები: ძვირფასეულობის მინიმალური რაოდენობა, რომელიც

დასჭირდება პრინცესას სასახლეში მიღწევისათვის.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 1 2 1 1 10 2

1 2 1 1 8 1

განმარტება. პირველ მაგალითში დრაკონი შეამჩნევს პრინცესას გაქცევას, როდესაც ამ

უკანასკნელს 1 მილი აქვს გავლილი. დრაკონი მას დაეწევა გამოქვაბულიდან 2 მილის

მანძილზე და აქ პრინცესას მოუწევს პირველი ძვირფასეულობის გადაგდება. დრაკონს უკან

დასაბრუნებლად და ძვირფასეულობის შესანახად დაეხარჯება 2 საათი, ხოლო პრინცესა ამ

დროში გამოქვაბულს დაშორდება 4 მილით. მეორედ დრაკონი პრინცესას დაეწევა 8 მილის

მანძილზე გამოქვაბულიდან და აქ პრინცესა მეორე ძვირფასეულობას გადაუგდებს, რის

შემდეგაც იგი ალბათ ასკინკილითაც კი მოასწრებს სასახლეში მისვლას.

მეორე მაგალითი პირველის ანალოგიურია, ოღონდ დრაკონი პრინცესას მეორედ ზუსტად

სასახლეში მისვლის მომენტში ეწევა, ამიტომ მეორე ძვირფასეულობა საჭირო აღარ არის. #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);

}

Page 62: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

62

ერთგანზომილებიანი მასივები

ვთქვათ, დასამუშავებლად მოგვცეს რომელიმე ქალაქის ტემპერატურული მონაცემები 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-ური ხის სიმაღლე ხეივანში.

გამოსატანი მონაცემები: ერთი მთელი რიცხვი – ყველაზე მაღალ ხესთან ხუთკუნჭულას

მისვლის დრო. პასუხის ერთადერთობა გარანტირებულია.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 8

129 341 86 209 532 61 600 98 6

Page 63: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

63

ანალიზი. ეს ამოცანა შეიძლება განვიხილოთ, როგორც მასივში მაქსიმუმის ძებნის ამოცანა,

ოღონდ გამოსატანია არა უშუალოდ მაქსიმუმის მნიშვნელობა, არამედ მისი ინდექსი მასივში.

მაქსიმუმის (და ანალოგიურად მინიმუმისაც) ძებნა მასივში ასე ხორციელდება: რაიმე ცვლადს

მივანიჭოთ მასივის პირველი ელემენტის მნიშვნელობა. დაწყებული მეორედან, მასივის ყველა

წევრი რიგრიგობით შევადაროთ ამ ცვლადს და თუ რომელიმე მათგანი მეტი იქნება ცვლადის

მიმდინარე მნიშვნელობაზე – შევცვალოთ ცვლადის მნიშვნელობა მასივის ამ ელემენტის

მნიშვნელობით. ამოცანაში ნაჩვენები მაგალითისათვის მაქსიმუმის მნიშვნელობა ასე

შეიცვლება:

მასივის ინდექსი 0 1 2 3 4 5 6 7

მასივის ელემენტი 129 341 86 209 532 61 600 98

მაქსიმუმი 129 341 341 341 532 532 600 600

აქვე აღვნიშნოთ, რომ მაქსიმუმის და მინიმუმის ძებნისას არ შეიძლება ცვლადის

სახელებად max-ს და min-ს გამოყენება, რადგან ეს სიტყვები C++-ში სპეციალურ ფუნქციებს

ჰქვიათ (მათ დანიშნულებას ერთ–ერთ მომდევნო თავში განვიხილავთ) და დარეზერვირებულ

სიტყვებად ითვლება. გაითვალისწინეთ, რომ ამოცანაში ხეები გადანომრილია 1–დან, ხოლო

მასივის ელემენტები 0–დან.

#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);

}

ამოცანა 72. კამათელი

მოცემულია კამათლის N-ჯერ (0 < N < 30000) გაგორების შედეგები. დაწერეთ პროგრამა,

რომელიც დაადგენს, თუ რომელი ქულა მოვიდა ყველაზე მეტჯერ.

შესატანი მონაცემები: პირველ სტრიქონში მოცემულია ერთი მთელი რიცხვი N –

კამათლის გაგორების რაოდენობა. მეორე სტრიქონი შეიცავს N ცალ მთელ რიცხვს s1, s2,...,sn

(1≤si≤6), სადაც si – i-ური გაგორების დროს მოსული ქულაა.

გამოსატანი მონაცემები: ერთი მთელი რიცხვი – ყველაზე მეტჯერ მოსული ქულა. თუ

პასუხი რამდენიმეა, შესაბანისი ქულები გამოიტანეთ ზრდადობით დალაგებული.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 15

3 1 5 2 2 6 5 4 1 4 5 6 5 4 4

4 5

ანალიზი. ეს ამოცანა გარკვეულწილად მოიცავს წინას (მასივში მაქსიმუმის მოძებნა).

განსხვავება იმაშია, რომ მაქსიმუმი შეიძლება რამდენიმე იყოს. გარდა ამისა, ჯერ დასათვლელია

თითოეული ქულის მოსვლის რაოდენობა, რისთვისაც ისეთ ხერხს გამოვიყენებთ, რომლიც სხვა

ამოცანებშიც ბევრჯერ დაგვჭირდება. ავიღოთ 7–ელემენტიანი მასივი (სინამდვილეში

ექვსელემენტიანი გვჭირდება და ნულოვან ინდექსზე მყოფ ელემენტს არ გამოვიყენებთ) და

Page 64: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

64

შემოსატანი რიცხვების შესაბამის ინდექსებზე მყოფ ელემენტებს რიგრიგობით დავუმატოთ 1.

ამოცანის მაგალითის მიხედვით ჯერ მესამე ელემენტს დავუმატოთ 1, შემდეგ – პირველს,

შემდეგ – მეხუთეს და ა.შ. პროგრამულ კოდში ეს ხორციელდება შემოსატანი მონაცემების

წაკითხვასთან ერთად. საბოლოოდ, თითოეულ ინდექსზე მივიღებთ შესაბამისი ქულის

მოსვლათა რაოდენობას.

რაოდენობების დათვლის შემდეგ ერთი ციკლით ვიპოვოთ მასივის მაქსიმუმი, ხოლო

შემდეგ კიდევ ერთი ციკლით ამოვბეჭდოთ ის ინდექსები, რომლებზეც მყოფი ელემენტები

მაქსიმუმის ტოლია. #include <iostream>

using namespace std;

int N,i,k, mx,a[7];

main() {

cin>>N;

for (i=0; i<N; i++){

cin>>k;

a[k]++;}

mx=a[1];

for (i=2; i<=6; i++)

if (a[i]>mx) mx=a[i];

for (i=1; i<=6; i++)

if (a[i]==mx) cout<<i<<” ”;

}

ამოცანა 73. აღმართები

მოცემულია საავტომობილო გზის სიმაღლეთა აღწერა გარკვეულ ტოლ მონაკვეთებში.

დაადგინეთ რამდენი აღმართია ამ გზაზე.

შესატანი მონაცემები: პირველ სტრიქონში მოცემულია ერთი მთელი რიცხვი N (1≤ N ≤100)

- გზის მონაკვეთთა რაოდენობა. მომდევნო სტრიქონში ჩაწერილია თითოეული მონაკვეთის

სიმაღლე (N ცალი მთელი დადებითი რიცხვი 1-დან 20-მდე დიაპაზონში).

გამოსატანი მონაცემები: ერთადერთ სტრიქონში გამოიტანეთ ერთი მთელი

არაუარყოფითი რიცხვი – აღმართების რაოდენობა გზაზე.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი

14

5 3 7 9 9 8 6 7 7 5 6 8 6 7

4

განმარტება: “აღმართები” ხაზგასმულია - 5 3 7 9 9 8 6 7 7 5 6 8 6 7

ანალიზი. ამოცანის მაგალითზე დაკვირვებითაც შეიძლება შევამჩნიოთ ფაქტი, რომ

აღმართი იწყება მაშინ, როდესაც რომელიმე რიცხვი მის მარცხენა მეზობელ რიცხვზე ნაკლები

ან ტოლია, ხოლო მარჯვენა მეზობელზე – მკაცრად ნაკლებია. გამონაკლისი მხოლოდ პირველი

რიცხვია, რომელსაც მარცხენა მეზობელი არ ჰყავს, მაგრამ მაინც შეიძლება იყოს აღმართის

დასაწყისი. ამ შემთხვევის ზოგად სქემაში მოსაქცევად შემოსატანი რიცხვები მასივში ჩავწეროთ

პირველი ინდექსიდან, ხოლო ნულოვან ინდექსზე ჩავწეროთ პირველი ელემენტის ტოლი

რიცხვი.

#include <iostream>

using namespace std;

int N,i,ans,a[105];

Page 65: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

65

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;

}

ამოცანა 74. მწვერვალები

მოცემულია მასივი, რომელიც აღწერს საავტომობილო გზის სიმაღლეს გარკვეულ ტოლ

მონაკვეთებში. მწვერვალი ვუწოდოთ ამ მასივის ისეთ ელემენტს, რომლის შემდეგ აღმართს

მოსდევს დაღმართი. იპოვეთ გზაზე მწვერვალების რაოდენობა. შემომავალი მონაცემების

პირველ სტრიქონში მოცემულია მონაკვეთების რაოდენობა, ხოლო მეორეში - თითოეული

მონაკვეთის სიმაღლე.

შესატანი მონაცემები: პირველ სტრიქონში მოცემულია ერთი მთელი რიცხვი N (1≤ N ≤100)

- გზის მონაკვეთთა რაოდენობა. მომდევნო სტრიქონში ჩაწერილია თითოეული მონაკვეთის

სიმაღლე (N ცალი მთელი დადებითი რიცხვი 1-დან 20-მდე დიაპაზონში).

გამოსატანი მონაცემები: ერთადერთ სტრიქონში გამოიტანეთ ერთი მთელი

არაუარყოფითი რიცხვი – მწვერვალების რაოდენობა გზაზე.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი

15

8 5 4 6 5 3 2 4 5 5 7 9 8 9 8

3

განმარტება: “მწვერვალები” ხაზგასმულია - 8 5 4 6 5 3 2 4 5 5 7 9 8 9 8

ანალიზი. ეს ამოცანა წინას მსგავსია. განსხვავება იმაშია, რომ პირველი და ბოლო

ელემენტები მწვერვალები ვერ იქნებიან, ხოლო ელემენტი, რომელიც მწვერვალი იქნება

მკაცრად მეტი უნდა იყოს ორივე მეზობელზე – მარცხნივაც და მარჯვნივაც.

#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;

}

Page 66: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

66

ამოცანა 75. გრძელი არითმეტიკა

გამოთვალეთ N! (N! იკითხება, როგორც „N–ის ფაქტორიალი“ და წარმოადგენს ყველა

მთელი რიცხვის ნამრავლ 1–დან N–მდე).

შესატანი მონაცემები: მოცემულია ერთი მთელი რიცხვი N (1≤N≤1000).

გამოსატანი მონაცემები: ერთი მთელი რიცხვი – N–ის ფაქტორიალი.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი

5 120

37 13763753091226345046315979581580902400000000

ანალიზი. ამოცანის სირთულე იმაში მდგომარეობს, რომ შემოსატანი რიცხვების

უმეტესობის ფაქტორიალი არცერთი მთელი ტიპის დიაპაზონში არ თავსდება. სწორედ ასეთ

შემთხვევაში იტყვიან, რომ საქმე გვაქვს ე.წ. „გრძელ არითმეტიკასთან“ (ზოგჯერ დიდი

რიცხვების არითმეტიკასაც უწოდებენ) და ასეთი ამოცანების ამოსახსნელად მასივს იყენებენ.

მთელი რიცხვის თანრიგები შევუსაბამოთ მასივის ელემენტებს. უხეში შეფასებითაც ჩანს, რომ

ყველაზე დიდი შემოსატანი რიცხვის – 1000–ის ფაქტორიალი 3000–ნიშნაზე მეტი ვერ იქნება

(ყველა გადასამრავლებელი რიცხვის თანრიგების რაოდენობა რომ შევკრიბოთ), ამიტომ

ავიღოთ 3000–ელემენტიანი მასივი და ელემენტი ინდექსით 3000, ჩავთვალოთ პასუხის

ერთეულთა თანრიგად, ელემენტი ინდექსით 2999, ჩავთვალოთ ათეულთა თანრიგად და ა.შ.

ჩავწეროთ a[3000]–ში 1 (სხვებში თავიდან 0–ები წერია) და მასივის ყველა ელემენტი

რიგრიგობით გადავამრავლოთ რიცხვებზე 2–დან N–მდე. ყოველი გადამრავლების შემდეგ

მასივის ზოგიერთ ელემენტში გაჩენილი „ზედმეტი“ თანრიგები (მომდევნო გადამრავლების წინ

ყველა ელემენტი მკაცრად ერთთანრიგიანი უნდა გახდეს) გადავანაცვლოთ მეზობელ მარცხენა

თანრიგში. ქვემოთ ცხრილში ბიჯების მიხედვით ნაჩვენებია 5!–ის გამოთვლა:

საწყისი მდგომარეობა 0 0 0 0 0 0 1

გამრავლება 2–ზე 0 0 0 0 0 0 2

ერთთანრიგიანზე დაყვანა 0 0 0 0 0 0 2

გამრავლება 3–ზე 0 0 0 0 0 0 6

ერთთანრიგიანზე დაყვანა 0 0 0 0 0 0 6

გამრავლება 4–ზე 0 0 0 0 0 0 24

ერთთანრიგიანზე დაყვანა 0 0 0 0 0 2 4

გამრავლება 5–ზე 0 0 0 0 0 10 20

ერთთანრიგიანზე დაყვანა 0 0 0 0 1 2 0

5!=120 და ჩვენც მივიღეთ 120, ოღონდ თითო–თითო ციფრად. ასევე მივიღებთ ნებისმიერი

რიცხვის ფაქტორიალს, თუმცა ამობეჭდვისას ბეჭდვა უნდა დავიწყოთ ნულისაგან

განსხვავებული პირველი ციფრისაგან, რის საპოვნელადაც კიდევ ერთი ციკლი დაგვჭირდება. #include<iostream>

using namespace std;

int a[3001],i,j,k,N;

int main(){

cin>>N;

a[3000]=1;

for (i=2; i<=N; i++) { for (j=1; j<=3000; j++) {

a[j]=a[j]*i; } for (j=3000; j>=1; j--) { a[j-1]+=a[j]/10; a[j]=a[j]%10; } } for (j=1; j<=3000; j++) if (a[j]!=0) break; for(i=j; i<=3000; i++) cout<<a[i];

}

Page 67: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

67

ამოცანა 76. თამაში

(IOI, მერვე საერთაშორისო ოლიმპიადა, უნგრეთი, 1996 წელი)

განვიხილოთ შემდეგი თამაში ორი მოთამაშისათვის: სათამაშო დაფაზე დაწერილია

მთელი დადებითი რიცხვების მიმდევრობა. მოთამაშეები სვლებს აკეთებენ რიგ-რიგობით. სვლა

მდგომარეობს შემდეგში: მოთამაშე ირჩევს მიმდევრობის რომელიმე კიდურა წევრს (მარცხენას

ან მარჯვენას). არჩეული რიცხვი დაფიდან იშლება. თამაში დამთავრდება მაშინ, როცა დაფაზე

ყველა რიცხვი წაიშლება. პირველი მოთამაშე იმ შემთხვევაში გაიმარჯვებს, თუ მეორე

მოთამაშის მიერ არჩეული ჯამი მეტი არ იქნება მის მიერ არჩეული რიცხვების ჯამზე.

გაითვალისწინეთ, რომ მეორე მოთამაშე საუკეთესო ალგორითმით თამაშობს.

თამაშს ყოველთვის პირველი მოთამაშე იწყებს.

ცნობილია, რომ თუ დაფაზე თავიდან დაწერილი მიმდევრობის წევრთა რაოდენობა

ლუწია, მაშინ პირველ მოთამაშეს მოგების შანსი აქვს. დაწერეთ პროგრამა, რომელშიც

რეალიზებული იქნება პირველი მოთამაშის მომგებიანი სტრატეგია. საწყისი მიმდევრობის

წევრთა რაოდენობა N ყოველთვის ლუწია და 2<=N<=100.

ანალიზი. პირველი სვლის გაკეთებისას პირველ მოთამაშეს სულ 2 ვარიანტი აქვს:

აირჩიოს მიმდევრობის პირველი რიცხვი ან აირჩიოს მიმდევრობის ბოლო რიცხვი. პირველ

შემთხვევაში მეორე მოთამაშე იძულებული ხდება აუცილებლად ლუწ ადგილზე მდგომი

რიცხვი აიღოს, მეორე შემთხვევაში პირიქით – იძულებული ხდება კენტ ადგილზე მდგომი

რიცხვი აიღოს. პირველ მოთამაშეს შეუძლია იგივე სიტუაცია შექმნას მეორე და მომდევნო

სვლების წინ. გამოდის, რომ პირველ მოთამაშეს შეუძლია აირჩიოს მხოლოდ კენტ ან მხოლოდ

ლუწ ადგილებზე მდგომი რიცხვები და მეორე მოთამაშე მას ხელს ვერ შეუშლის. აქედან

გამომდინარე, პირველმა მოთამაშემ ცალ–ცალკე უნდა დათვალოს კენტ და ლუწ ადგილებზე

მდგომი რიცხვების ჯამები და უკეთესი ვარიანტი აირჩიოს. თუ ჯამები ტოლია, მნიშვნელობა

არა აქვს რომელს ამოირჩევს – თამაში ფრედ დამთავრდება.

ამოცანა 77. წილადის პერიოდი

განვიხილოთ m/n წესიერი წილადი, სადაც m და n ნატურალური რიცხვებია. თუკი m-ის n-

ზე გაყოფისას გაყოფა შეწყდა, იტყვიან, რომ m/n წილადის პერიოდი არის 0, ხოლო თუ გაყოფის

პროცესი უსასრულოდ გაგრძელდა, მაშინ განაყოფში აუცილებლად მოიძებნება რიცხვთა

განმეორებადი მიმდევრობა, რომელსაც წილადის პერიოდს უწოდებენ.

დაწერეთ პროგრამა, რომელიც იპოვის წესიერი წილადის პერიოდს.

შესატანი მონაცემები: ორი მთელი რიცხვი m და n (2≤ m < n ≤1000).

გამოსატანი მონაცემები: ერთი მთელი რიცხვი – წილადის პერიოდი.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 3 4 0

19 28 857142

22 23 9565217391304347826086

ანალიზი. შემოვიღოთ 1000-ელემენტიანი ერთგანზომილებიანი k მასივი და შევავსოთ 0-

ებით. რადგან მოცემული წილადი წესიერია, თავიდან m რიცხვი, შემდეგში კი გაყოფის

შედეგად დარჩენილი ნაშთი ციკლში გავამრავლოთ 10-ზე და გავყოთ n-ზე. თითოეულ ბიჯზე

მიღებული ნაშთის შესაბამის ინდექსზე k მასივში ჩავწეროთ 1-იანი – თუკი იქ 0 დაგვხვდება,

ხოლო თუკი 1-იანი დაგვხდება – პროცესი შევწყვიტოთ, რადგან ეს ნიშნავს, რომ ნაშთი

განმეორდა და ყველაფერი თავიდან იწყება.

Page 68: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

68

#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]++;

}

}

ამოცანა 78. სრულყოფილი კრებული

ხორვატიის ღია პირველობა ინფორმატიკაში (2007/08 წელი, შეჯიბრი 2)

მირკომ სხვენზე ძველისძველი საჭადრაკო დაფა იპოვა ჭადრაკის ფიგურების კრებულთან

ერთად. სამწუხაროდ, კრებულში მხოლოდ თეთრი ფერის ფიგურებია და ისინიც არ არიან

სრულყოფილად დაკომპლექტებული. ერთი ფერის ფიგურების სრულყოფილი კრებული უნდა

შეიცავდეს: 1 მეფეს, 1 ლაზიერს, 2 ეტლს, 2 კუს, 2 მხედარს და 8 პაიკს.

მირკოს სურს იცოდეს, რამდენი ფიგურის დამატება ან მოშორებაა საჭირო ფიგურათა

თითოეული ტიპისათვის სრულყოფილი კრებულის მისაღებად.

შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია ექვსი მთელი რიცხვი. ყოველი

მათგანი მოთავსებულია 0–დან 10–მდე დიაპაზონში (ჩათვლით). რიცხვები თანმიმდევრულად

აღნიშნავენ მეფის, ლაზიერის, ეტლის, კუს, მხედრისა და პაიკის იმ რაოდენობებს, რომელიც

მირკომ იპოვა.

გამოსატანი მონაცემები: ერთადერთ სტრიქონში უნდა გამოიტანოთ ექვსი მთელი რიცხვი.

ფიგურების ის რაოდენობა, რომელიც მირკომ უნდა დაამატოს ან მოიშოროს, რათ კრებული

სრულყოფილი გახდეს. დამატების შემთხვევაში გამოსატანი რიცხვი დადებითი უნდა იყოს,

ხოლო მოშორების შემთხვევაში – უარყოფითი.

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი 0 1 2 2 2 7 1 0 0 0 0 1 2 1 2 1 2 1 -1 0 0 1 0 7

ანალიზი. ერთ–ერთ მასივში წინასწარ ჩავწეროთ სრულყოფილი კრებულისთვის საჭირო

რაოდენობები. შემოსატანი რიცხვების წაკითხვისას გამოვთვალოთ და დავბეჭდოთ შესაბამისი

სხვაობები. კოდში ნაჩვენებია, თუ როგორ ავიცილოთ თავიდან ზედმეტი ჰარის ბეჭდვა

სტრიქონის ბოლოს.

#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" );

}

Page 69: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

69

ამოცანა 79. მოდული

ხორვატიის ღია პირველობა ინფორმატიკაში (2006/07 წელი, შეჯიბრი 1)

მოცემულია ორი მთელი რიცხვი A და B. A მოდულით B ვუწოდოთ A–ს B–ზე გაყოფის

ნაშთს. მაგალითად, რიცხვებისათვის 7, 14, 27 და 38 მივიღებთ, რომ შესაბამისად 1, 2, 0 და 2,

მოდულით 3. დაწერეთ პროგრამა, რომელიც მოცემული 10 რიცხვისათვის გამოითვლის, თუ

რამდენ განსხვავებულ რიცხვს მივიღებთ, თითოეულ მათგანზე 42–ის მოდულით ჩატარებული

ოპერაციისას.

შესატანი მონაცემები: ათი სტრიქონიდან თითოეულში თითო მთელი რიცხვი არაუმეტეს

1000–ისა.

გამოსატანი მონაცემები: ერთადერთ სტრიქონში ერთი მთელი რიცხვი – განსხვავებული

რიცხვების რაოდენობა შემოსატან რიცხვებზე 42–ის მოდულით ჩატარებული ოპერაციისას.

შემავალი მონაცემი შემავალი მონაცემი შემავალი მონაცემი 1

2

3

4

5

6

7

8

9

10

42

84

252

420

840

126

42

84

420

126

39

40

41

42

43

44

82

83

84

85

გამომავალი მონაცემი გამომავალი მონაცემი გამომავალი მონაცემი 10 1 6

განმარტება. პირველ მაგალითში მიიღება ნაშთები 1, 2, 3, 4, 5, 6, 7, 8, 9 და 10.

მეორე მაგალითში ყველა რიცხვი უნაშთოდ იყოფა 42–ზე და ყველა ნაშთი 0–ია

მესამე მაგალითში მიიღება ნაშთები: 39, 40, 41, 0, 1, 2, 40, 41, 0 და 1. სულ 6 განსხვავებული

რიცხვი.

ანალიზი. თითოეული რიცხვისათვის გამოვთვალოთ 42–ზე გაყოფის ნაშთი და შესაბამის

ინდექსზე რაიმე მასივში ჩავწეროთ 1 (თუ იგივე ნაშთს მივიღებთ, ერთიანი განმეორებით

ჩაიწერება). შემდეგ ამ მასივში დავთვალოთ 1–იანების რაოდენობა, რაც იქნება კიდევაც

ამოცანის პასუხი. #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;

}

Page 70: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

70

ამოცანა 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

ანალიზი. ყოველი გენერირებული რიცხვის შესაბამის ინდექსზე ჩავწეროთ true, თუკი ამ

ინდექსზე false წერია, წინააღმდეგ შემთხვევაში ციკლი შევწყვიტოთ და დავბეჭდოთ ციკლის

იტერაციათა რაოდენობა.

#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;

}

Page 71: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

71

ორგანზომილებიანი მასივები

С++–ში (და პროგრამირების სხვა ენებშიც) განსაზღვრულია მრავალგანზომილებიანი

მასივები. ასეთი მასივების უმარტივეს ფორმას წარმოადგენს ორგანზომილებიანი მასივი,

რომელიც შეგვიძლია წარმოვიდგინოთ, როგორც ერთგანზომილებიანი მასივების მასივი.

20x25-ზე ზომის ორგანზომილებიანი მასივის გამოცხადება ხდება შემდეგნაირად: int d[20][25];

მიმართვა ამ მასივის ელემენტზე, ვთქვათ, ინდექსებით 2 და 6, ასე ხდება: d[2][6].

ორგანზომილებიანი მასივი შეიძლება წარმოვადგინოთ ცხრილის (ან მატრიცის) სახით:

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

ცხრილში ინდექსები რუხი ფონითაა აღნიშნული. ელემენტების და ინდექსების

ურთიერთკავშირი: d[0][4]=23, d[1][3]=10, d[2][0]=16 და ა.შ.

რეალურად მრავალგანზომილებიანი მასივები მეხსიერებაში ერთგაზომილებიანი მასივის

სახით არიან შენახული. განსხვავება მხოლოდ იმაშია, რომ საჭირო ელემენტის მისამართის

გამოსათვლელად უფრო რთული ოპერაციებია ჩასატარებელი. მაგალითად, თუ მოცემულია

მასივი d[10][20][15] და საჭიროა მიმართვა ელემენტზე d[2][5][8], კომპილატორმა ჯერ

უნდა გამოთვალოს მერამდენე იქნებოდა ეს ელემენტი იგივე მასივის „ერთგანზომილებიან“

წარმოდგენაში: 2x20x15+5x15+8=683, შემდეგ კი მასივის ტიპის ზომის მიხედვით

გადათვალოს შესაბამისი რაოდენობის ბაიტები მასივის დასაწყისიდან, ანუ d[0][0][0]

ელემენტიდან. მრავალგანზომილებიანი მასივების გამოყენებისას ბევრი დრო იხარჯება

ელემენტთა მისამართების გამოთვლაზე, ამიტომ მიმართვა ასეთი მასივების ელემენტებზე

უფრო ნელა მუშაობს, ვიდრე ერთგანზომილებიანი მასივების შემთხვევაში.

ორგანზომილებიანი მასივის მიერ დაკავებული მეხსიერება მისი განზომილებებისა და

მასივის ტიპის ზომის ნამრავლის ტოლია. მაგალითად, int d[20][25] მასივი მეხსიერებაში

დაიკავებს 20x25x4=2000 ბაიტს, ხოლო double d[20][25][10] მასივი დაიკავებს

20x25x10x8=40000 ბაიტს.

Page 72: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

72

ამოცანა 81. მთავარი დიაგონალები

იპოვეთ NxN (N<100) მასივის მთავარი დიაგონალების ჯამი.

შესატანი მონაცემები: პირველ სტრიქონში ერთი მთელი რიცხვი: N. მომდევნო N

სტრიქონიდან თითოეულში N ცალი მთელი რიცხვი დიაპაზონიდან 1..1000.

გამოსატანი მონაცემები: ორი მთელი რიცხვი - მთავარ დიაგონალებზე მდგომი

ელემენტების ჯამი. პირველად გამოიტანეთ დიაგონალი, რომელიც იწყება ზედა მარცხენა

კუთხეში და მთავრდება ქვედა მარჯვენა კუთხეში.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 3

18 21 10

15 13 9

26 44 22

53 49

განმარტება. 18+13+22=53 და 10+13+26=49.

ანალიზი. მასივს აქვს ორი მთავარი დიაგონალიდან პირველში, რომლის ბოლოებსაც

წარმოადგენენ ელემენტები [1][1] და [N][N], ორივე ინდექსი თანაბრად იზრდება და ყოველთვის

ტოლია, ხოლო მეორე დიაგონალში, რომლის წვეროებსაც წარმოადგენენ [1][N] და [N][1] –

მარცხენა ინდექსი იზრდება, ხოლო მარჯვენა მცირდება. #include <iostream> using namespace std;

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;

}

ამოცანა 82. დიაგონალის ზემოთ

იპოვეთ NxN (N<100) მასივის მთავარი დიაგონალის (რომლის ბოლოებსაც წარმოადგენენ

ელემენტები [1][1] და [N][N]) ზემოთ მდგარი წევრების ჯამი.

შესატანი მონაცემები: პირველ სტრიქონში ერთი მთელი რიცხვი: N. მომდევნო N

სტრიქონიდან თითოეულში N ცალი მთელი რიცხვი დიაპაზონიდან 1..1000.

გამოსატანი მონაცემები: ერთი მთელი რიცხვი - მთავარი დიაგონალის ზემოთ მდგომი

ელემენტების ჯამი.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 3

18 21 10

15 13 9

26 44 22

40

განმარტება. 21+10+9=40.

Page 73: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

73

ანალიზი. დიაგონალის ზემოთ მდებარე ნებისმიერი ელემენტისათვის მარცხენა ინდექსი

მარჯვენაზე ნაკლებია, ხოლო დიაგონალის ქვემოთ მყოფი ელემენტებისათვის – პირიქით.

ელემენტების აჯამვა უშუალოდ მასივის ელემენტების კითხვის დროსაც შეიძლება. #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;

}

ამოცანა 83. კვადრატები

100100 ზომის სიბრტყეზე მოცემულია N ცალი (1<N<100) კვადრატი, რომელთა

გვერდები კოორდინატთა ღერძების პარალელურია. განსაზღვრეთ იმ არის ფართობი,

რომელიც ამ კვადრატებს ერთად უკავიათ (წერტილი ეკუთვნის ამ არეს, თუკი ის

მდებარეობს ერთი კვადრატის შიგნით მაინც). კვადრატთა წვეროები მდებარეობენ

მთელი მნიშვნელობის მქონე კოორდინატებში.

შესატანი მონაცემები: პირველ სტრიქონში მოცემულია კვადრატების რაოდენობა N.

მომდევნო N სტრიქონიდან თითოეულში მოცემულია ჰარით გაყოფილი სამი რიცხვი a,

b და c – კვადრატის მახასიათებლები, სადაც a და b კვადრატის ზედა მარცხენა

წვეროს კოორდინატებია, ხოლო c კვადრატის გვერდის სიგრძე. 1a+c,b+c100).

გამოსატანი მონაცემები: ერთადერთ სტრიქონში – კვადრატების მიერ დაფარული არის

ფართობი.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 3

4 6 10

7 8 3

12 9 4

108

ანალიზი: ცარიელი არე წარმოვიდგინოთ 0-ებად, ხოლო კვადრატების მიერ დაფარული

არე 1-ებით შევავსოთ. ყველა კვადრატის აგების შემდეგ დავთვალოთ 1-იანების

რაოდენობა. #include <iostream>

using namespace std; int n,i,j,a,b,c,x,sum=0,arr[101][101];

main () {

cin>>n;

for (x = 1; x <=n; x++) {

cin>>a>>b>>c;

for (i = a; i <a+c; i++) {

for (j = b; j<b+c; j++){

arr[i][j]=1;

} } }

for (i = 0; i <=100; i++) {

for (j = 0; j<=100; j++){

if (arr[i][j]==1) sum++;

} }

cout<<sum<<endl;

}

Page 74: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

74

ამოცანა 84. ჯვრები და ნულები

3x3 ზომის დაფაზე ორი მოთამაშე რიგ-რიგობით წერს შესაბამისად ჯვარს ან ნულს.

მოგებულია ის მოთამაშე, რომელიც საკუთარ ფიგურას განალაგებს რომელიმე ჰორიზონტალის,

ვერტიკალის ან დიაგონალის სამივე უჯრაში. მოცემულია დაფის საბოლოო მდგომარეობა,

სადაც “+” აღნიშნავს ჯვარს, “0” – ნულს, ხოლო “*” – ცარიელ უჯრას (თუკი ასეთი არის).

დაწერეთ პროგრამა, რომელიც იპოვის გამარჯვებულ მოთამაშეს.

შესატანი მონაცემები: სამ სტრიქონში მოცემულია სამ–სამი სიმბოლო – “+”,“0” ან “*”.

გამოსატანი მონაცემები: თუ პირველმა მოთამაშემ მოიგო, გამოიტანეთ სიტყვა

“FIRST”, თუ მეორემ – “SECOND”, თუ ვერცერთმა – “NO ONE”. შესატანი

მონაცემები კორექტულია.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი +0*

+00

+*0

FIRST

ანალიზი. 3x3 ზომის დაფაზე.თითოეული მოთამაშისათვის მომგებიანი სიტუაციის 8

განლაგება არსებობს: 3 ვერტიკალურად, 3 ჰორიზონტალურად და ორი დიაგონალურად. მცირე

ზომის დაფებისათვის შესაძლებელია ყველა ვარიანტის ჩამოწერა (ჩვენს შემთხვევაში 16-ის) და

თუ არცერთი არ შესრულდა, მაშინ ყაიმი იქნება. თუმცა დიდი ზომის მასივებისათვის ასეთი

მიდგომა გაუმართლებელია. nxn ზომის სიმბოლური მასივი უმჯობესია გადავწეროთ ამავე

ზომის რიცხვით მასივში, სადაც ‘+’-ის ნაცვლად ჩავწეროთ 1, ‘O’-ს ნაცვლად -1, ხოლო ‘*’-ის

ნაცვლად 0. შემდეგ ცალ-ცალკე ავჯამოთ ყველა ვერტიკალი, ყველა ჰორიზონტალი და ორივე

დიაგონალი. თუკი რომელიმე ამ ჯამთაგან n-ის ტოლია – გაუმარჯვია პირველ მოთამაშეს, თუ

–n-ის ტოლია – მეორე მოთამაშეს, ხოლო თუკი არცერთი ჯამი არ უდრის n-ს ან –n-ს, თამაში

ყაიმით დამთავრებულა. #include<iostream>

using namespace std;

int a,s,d[5][5],y[8],f,g,h,j,k,l,i;

char x[3][3];

main(){

for(i=0;i<3;i++){

for(a=0;a<3;a++){

cin>>x[i][a];

if(x[i][a]=='*') d[i][a]=0;

if(x[i][a]=='0') d[i][a]=-1;

if(x[i][a]=='+') d[i][a]=1;

}}

y[0]=d[0][0]+d[1][1]+d[2][2];

y[1]=d[0][2]+d[1][1]+d[2][0];

y[2]=d[0][0]+d[0][1]+d[0][2];

y[3]=d[1][0]+d[1][1]+d[1][2];

y[4]=d[2][0]+d[2][1]+d[2][2];

y[5]=d[0][0]+d[1][0]+d[2][0];

y[6]=d[0][1]+d[1][1]+d[2][1];

y[7]=d[0][2]+d[1][2]+d[2][2];

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";}

Page 75: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

75

ამოცანა 85. რიცხვები დაფაზე

NxN (3<=N<=100) ზომის დაფაზე, რომელიც საჭადრაკო დაფის ანალოგიურადაა

დაყოფილი შავ და თეთრ უჯრედებად, ყოველ უჯრედში ჩაწერილია ორნიშნა რიცხვი. იპოვეთ

შავ უჯრედებში ჩაწერილი რიცხვების ჯამი, თუკი დაფის ზედა მარცხენა უჯრედი თეთრია.

შესატანი მონაცემები: პირველ სტრიქონში მოცემულია ერთი მთელი რიცხვი – N, მეორე

სტრიქონდან N+1 სტრიქონამდე თითოეულში მოცემულია N ცალი ორნიშნა რიცხვი.

გამოსატანი მონაცემები: ერთადერთ სტრიქონში ერთი მთელი რიცხვი – შავ უჯრედებში

ჩაწერილი რიცხვთა ჯამი.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 3

12 25 78

19 38 91

37 42 63

177

ანალიზი. თითოეული შავი უჯრედის ინდექსთა ჯამი არის კენტი, ხოლო თითოეული

თეთრი უჯრედის ინდექსთა ჯამი – ლუწი. მასივიც ამ პირობით უნდა გადავამოწმოთ.

#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;

}

ამოცანა 86. ორი ლაზიერი

საჭადრაკო დაფაზე მოთავსებული ორ – თეთრ და შავ ლაზიერს შეუძლია ერთმანეთის

მოკვლა, თუ ისინი ერთსა და იმავე ჰორიზონტალზე, ვერტიკალზე ან დიაგონალზე დგანან.

დაწერეთ პროგრამა, რომელიც გაარკვევს შეუძლიათ თუ არა ორ ლაზიერს ერთმანეთის მოკვლა.

შესატანი მონაცემები: პირველ სტრიქონში მოცემულია ორი მთელი რიცხვი – თეთრი

ლაზიერის კოორდინატები. მეორე სტრიქონში მოცემულია ორი მთელი რიცხვი – შავი

ლაზიერის კოორდინატები. კოორდინატების დიაპაზონია 1–დან 8–მდე.

გამოსატანი მონაცემები: დადებითი პასუხის შემთხვევაში პროგრამამ გამოიტანოს

“YES”, წინააღმდეგ შემთხვევაში – “NO. შესატანი მონაცემები კორექტულია.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 1 5

7 3

NO

3 6

1 8

YES

ანალიზი. იოლი დასადგენია, დგანან თუ არა ლაზიერები ერთ ჰორიზონტალზე ან ერთ

ვერტიკალზე. ამისათვის, საკმარისია შესაბამისი კოორდინატების ტოლობა. ერთ დიაგონალზე

დგომის პირობა კი მაშინ კმაყოფილდება, თუ შესაბამის კოორდინატთა სხვაობების

აბსოლუტური მნიშვნელობები უდრის ერთმანეთს.

Page 76: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

76

#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”;

}

ამოცანა 87. ძროხების ბოულინგი – Cow Bowling [IOI, 1994]

USACO, 2005/06 წლის დეკემბრის შეჯიბრი, “ბრინჯაოს” დივიზიონი

ბოულინგის თამაშის დროს ძროხები არ იყენებენ ჩვეულებრივ ბურთებს. თითოეული

მათგანი იღებს ერთ რიცხვს (დიაპაზონში 1..99) და ისე ეწყობიან, რომ ჰქმნიან სტანდარტულ

საბოულიგე სამკუთხედს, როგორც ეს ქვემოთაა ნაჩვენები: 7

3 8

8 1 0

2 7 4 4

4 5 2 6 5

სხვა ძროხები დგებიან სამკუთხედის წვეროში და იწყებენ მოძრაობას სამკუთხედის

ფუძისაკენ. ყოველ სვლაზე ძროხას შეუძლია გადავიდეს დიაგონალზე მდგომი ორი მეზობელი

ძროხიდან ერთ–ერთთან და მისი შედეგი ტოლია ყველა იმ ძროხის რიცხვის ჯამისა,

რომელთანაც ის საკუთარი მოძრაობის დროს მივა. ბოულინგში გამარჯვებულად ითვლება ის

ძროხა, რომელიც მაქსიმალურ ქულას მოაგროვებს.

N (1<=N<=350) სტრიქონისაგან შედგენილი სამკუთხედისათვის განსაზღვრეთ უდიდესი

შესაძლებელი ჯამი.

შესატანი მონაცემები: პირველ სტრიქონში მოცემულია ერთი მთელი რიცხვი – N.

მომდევნო N სტრიქონიდან თითოეულში: სტრიქონი i+1 შეიცავს i ცალ რიცხვს და წარმოადგენს

სამკუთხედის i–ურ სტრიქონს.

გამოსატანი მონაცემები: ერთი მთელი რიცხვი – უდიდესი შესაძლებელი ჯამი აღწერილი

წესით მოძრაობისას.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 5

7

3 8

8 1 0

2 7 4 4

4 5 2 6 5

30

განმარტება. ვარსკვლავებით ნაჩვენებია ოპტიმალური გზა.

7

*

3 8

*

8 1 0

*

2 7 4 4

*

4 5 2 6 5

Page 77: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

77

ანალიზი. მოცემული მაგალითისათვის ვთქვათ, ჩვენ უკვე შევარჩიეთ მაქსიმალური გზა

პირველ ოთხ სტრიქონში და მხოლოდ მეხუთე სტრიქონში დაგვრჩა რიცხვი ასარჩევი. თუკი

ჩვენ ვდგავართ მეოთხე სტრიქონის პირველ ელემენტზე (რიცხვი 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]);

}

ამოცანა 88. თამაში ფურცელზე

http://codeforces.com/problemset/problem/203/ B

მოწყენილობისაგან თავგაბეზრებულმა ვალერიმ ასეთი გასართობი იპოვა: მან აიღო n×n

ზომის თეთრი უჯრედოვანი ფურცელი და დაიწყო მასზე უჯრედების შავად გაფერადება. სულ

მან გააფერადა m ცალი უჯრედი. ახლა ვალერის აინტერესებს საკითხი: რომელი სვლის შემდეგ

შეიძლებოდა მოძებნილიყო ფურცელზე 3×3 ზომის კვადრატი.

დაწერეთ პროგრამა, რომელიც იპოვის მინიმალური ნომრის სვლას, რომლის შემდეგაც

ფურცელზე წარმოიქმნა 3×3 ზომის კვადრატი, ან გაარკვევს, რომ ასეთი სვლა არ არსებობს.

Page 78: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

78

შესატანი მონაცემები: პირველ სტრიქონში მოცემულია ორი მთელი რიცხვი – n და m

(1≤n≤1000, 1≤m≤min(n·n,105)) – უჯრედოვანი ფურცლის ზომა და გაფერადებული უჯრედების

რაოდენობა. მომდევნო m სტრიქონიდან თითოეულში მოცემულია გაფერადებული უჯრედის

აღწერა: i–ურ სტრიქონი შეიცავს ორ xi, yi (1≤xi,yi≤n) რიცხვს: i–ურ სვლაზე შეფერადებული

უჯრედის კოორდინატს.

სვლები შემოდის ნომრების ზრდადობის მიხედვით და არ მეორდება. უჯრედოვანი

ფურცელი გადანომრილია ზემოდან ქვემოთ და მარცხნიდან მარჯვნივ.

გამოსატანი მონაცემები: ერთი მთელი რიცხვი – სვლის მინიმალური ნომერი, რომლის

შემდეგაც ფურცელზე წარმოიქმნა 3×3 ზომის კვადრატი. თუ ასეთი სვლა არ არსებობს,

გამოიტანეთ –1.

შესატანი მონაცემების მაგალითი შესატანი მონაცემების მაგალითი 4 11

1 1

1 2

1 3

2 2

2 3

1 4

2 4

3 4

3 2

3 3

4 1

4 12

1 1

1 2

1 3

2 2

2 3

1 4

2 4

3 4

3 2

4 2

4 1

3 1

შესაბამისი გამოსატანი მონაცემი შესაბამისი გამოსატანი მონაცემი 10 -1

ანალიზი. ახალი უჯრის გაფერადების შემდეგ ორგანზომილებიან მასივის ყველა იმ

ელემენტში, რომელიც დაშორებულია მოცემული უჯრიდან არაუმეტეს 2 ერთეულით და

მდებარეობენ ამ უჯრის ქვემოთ და მარჯვნივ, დავუმატოთ 1–იანები. ამასთან, ყოველი

დამატებისას შევამოწმოთ, რომელიმე უჯრაში ხომ არ მივიღეთ 9.

#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;

}

Page 79: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

79

ამოცანა 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

შესატანი მონაცემები: პირველ სტრიქონში მოცემულია ერთი მთელი რიცხვი – N.

გამოსატანი მონაცემები: N ცალი სტრიქონიდან თითოეულში N ცალი რიცხვი – ამოცანაში

აღწერილი წესით.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 3 1 2 3

8 9 4

7 6 5

ანალიზი. სულ გვაქვს მოძრაობის 4 მიმართულება. თითოეული მათგანისათვის

დავწეროთ ცალკე ციკლი და ეს ციკლები მოვაქციოთ მეხუთე ციკლში, რომელიც შესრულდება

მანამ, ვიდრე არ ამოიწურება სვლების რაოდენობა.

#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;

}

for (i = 1 ;i <= n ;i ++) {

for (j = 1 ;j <= n - 1 ;j ++)

printf("%d ",a[i][j]);

Page 80: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

80

printf("%d\n",a[i][n]);

}

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” მოთხოვნისათვის გამოიტანეთ თითო რიცხვი

თითო სტრიქონში. პასუხები გამოიტანეთ იმავე თანმიმდევრობით, როგორც ეს შემომავალ

მონაცემებშია.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 3 3 5

1 2 3

4 5 6

7 8 9

g 3 2

r 3 2

c 2 3

g 2 2

g 3 2

8

9

6

2 3 3

1 2 4

3 1 5

c 2 1

r 1 2

g 1 3

5

Page 81: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

81

ანალიზი: თუ ვიანგარიშებთ შესატანი მონაცემების მაქსიმალური მნიშვნელობებისათვის,

ცხადია, რომ პროცესის სიმულაცია (სტრიქონების ან სვეტების ელემენტებისათვის ადგილის

გაცვლა) ძალიან ბევრ ოპერაციას მოითხოვს. უფრო სწრაფი ამოხსნისათვის ერთგანზომილებიან

მასივებში ჩავწეროთ სტრიქონებისა და სვეტების ნომრები და შემდგომში მხოლოდ ამ ნომრებს

(ანუ მხოლოდ ორ–ორ რიცხვს) გავუცვალოთ ადგილები.

#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;

}

}

Page 82: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

82

ბიტური ოპერაციები

ამოცანა 91. სახალისო თამაში

(მოსკოვის გუნდური ოლიმპიადა ინფორმატიკაში, 2002/03)

მათემატიკის ლეგენდარულმა მასწავლებელმა იური პეტროვიჩმა მოიგონა სახალისო

თამაში რიცხვებით. მან მთელი რიცხვი გადაიყვანა ორობით სისტემაში და მიიღო ნულებისა და

ერთებისაგან შედგენილი მიმდევრობა (მაგ., 1910=100112). ამის შემდეგ მასწავლებელმა დაიწყო

მიმდევრობის წრიული წანაცვლება ისე, რომ ბოლო ციფრი ხდება პირველი, ხოლო ყველა

დანარჩენი წანაცვლდება ერთი პოზიციით მარჯვნივ. ცხადია, რომ ასეთი ქმედების გარკვეული

რაოდენობის შემდეგ მიღებული მიმდევრობები მეორდება. მასწავლებელმა ამოიწერა ყველა

მიმდევრობა, ვიდრე ისინი განმეორებას დაიწყებდნენ, თითოეული მათგანი გადაიყვანა უკან –

ათობით სისტემაში და მათ შორის ამოარჩია ყველაზე დიდი. მაგ. 19–ისათვის

10011

11001

11100

01110

00111

10011

თამაშის შედეგია რიცხვი 124+123+122+021+020=28.

დაწერეთ პროგრამა, რომელიც მოცემული რიცხვისათვის გამოიტანს თამაში შედეგს.

შესატანი მონაცემები: პირველ სტრიქონში ერთი მთელი რიცხვი – N (0N32767).

გამოსატანი მონაცემები: ერთი მთელი რიცხვი – თამაშის შედეგი.

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი

19 28

ანალიზი. რადგან ორობით ჩანაწერში თანრიგების რაოდენობა ბევრი არ არის, უბრალოდ

საჭიროა პროცესის სიმულაცია. რიცხვის ორობითი ჩანაწერის მარცხნივ წანაცვლებისათვის

საჭიროა ამ რიცხვის გამრავლება 2-ზე (მარჯვნივ წანაცვლებისათვის პირიქით - საჭიროა 2-ზე

გაყოფა). წანაცვლება წრიული რომ გამოვიდეს, უნდა ვაკონტროლოთ პირველი ციფრი 1-ია თუ

0. თუ 1-ია, ახალ რიცხვს 1 უნდა დავუმატოთ.

#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");

}

Page 83: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

83

ამოცანა 92. მარსიანელის გენომი

პლანეტა მარსზე აღმოაჩინეს ცოცხალი არსებები, რომელთა გენომი N (3<=N<100000) კენტი

რაოდენობის გენისაგან შედგება. ყველა გენი გენომის შიგნით დუბლირებულია, გარდა ერთისა.

თითოეულ გენს მინიჭებული აქვს ნომერი დიაპაზონიდან 1..1,000,000,000.

დაწერეთ პროგრამა, რომელიც იპოვის დუბლის არმქონე გენს.

შესატანი მონაცემები: პირველ სტრიქონში მოცემულია ერთი მთელი კენტი რიცხვი – N,

მეორე სტრიქონში N ცალი რიცხვი – მარსიანელის გენის ნომრები..

გამოსატანი მონაცემები: ერთადერთ სტრიქონში ერთი მთელი რიცხვი – დუბლის არმქონე

გენის ნომერი.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 7

12 25 25 78 29 12 78

29

ანალიზი. ვისარგებლოთ იმ ფაქტით, რომ 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;

}

ამოცანა 93. პატარა xor

http://codeforces.com/problemset/problem/252A.

პატარა პეტრეს ძალიან უყვარს მთელი დადებითი რიცხვებით შედგენილი მასივები.

ახლახან დედამ აჩუქა მას ერთი ასეთი მასივი, რომელიც ელემენტისაგან შედგება. პეტრემ

მაშინვე გადაწყვიტა, იპოვოს მასში თანმიმდევრულად განლაგებული n ელემენტებისაგან

შედგენილი ისეთი მონაკვეთი, რომელშიც შემავალი რიცხვების xor მაქსიმალური იქნება.

დაეხმარეთ მას.

შესატანი მონაცემები: პირველ სტრიქონში მოცემულია ერთი მთელი რიცხვი – n (1 ≤ n ≤ 100), მეორე სტრიქონში მოცემულია n ცალი მთელი დადებითი რიცხვი – მასივის წევრები,

რომელთაგან თითოეული მკაცრად ნაკლებია 230–ზე.

გამოსატანი მონაცემები: ერთადერთ სტრიქონში ერთი მთელი რიცხვი –

თანმიმდევრულად განლაგებული ელემენტებისაგან შედგენილი მაქსიმალური xor.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 5

1 2 1 1 2 3

3

1 2 7 7

4

4 2 4 8 14

განმარტება. პირველ მაგალითში მაქსიმალურ xor–ს იძლევა პირველი ორი ელემენტი,

ხოლო მეორე მაგალითში – მხოლოდ მესამე ელემენტი.

Page 84: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

84

ანალიზი. რადგან მასივის ელემენტთა რაოდენობა მცირეა, ორმაგი ციკლის გადავარჩიოთ

თანმიმდევრულად განლაგებული ელემენტების ყველა ვარიანტი (ვარიანტების რაოდენობა

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;

}

ამოცანა 94. Sum25 [Don Piele, 1982]

USACO 2001 წლის ზამთრის შეჯიბრი, “ნარინჯისფერი” დივიზიონი დაწერეთ პროგრამა, რომელიც მოცემული 7 ციფრისათვის (0 <= ციფრი <= 9) გამოითვლის

იმ ქვესიმრავლეების რაოდენობას, რომელთა ჯამიც 25-ის ტოლია. ციფრი “0”-ის ნაცვლად

შეკრებისას უნდა ჩაისვას 10.

მაგალითად, 5 0 1 5 4 3 7 სიმრავლიდან 25 მიიღება შემდეგი ქვესიმრავლეებით: 5 0 3 7

5 1 5 4 3 7

5 0 1 5 4

0 1 4 3 7

0 5 3 7

შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია შვიდი ციფრი.

გამოსატანი მონაცემები: ერთადერთ სტრიქონში ერთი მთელი რიცხვი – ქვესიმრავლეების

რაოდენობა, რომელთა ჯამიც 25-ის ტოლია.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 5 0 1 5 4 3 7 5

ანალიზი. 7–ელემენტიანი სიმრავლის ყველა ქვესიმრავლის რაოდენობა არ აღემატება 2–

ის მეშვიდე ხარისხს (ანუ 128–ს, რაც ძალზე მცირე რიცხვია), ამიტომ საჭიროა ყველა მათგანის

გენერაცია. ამისათვის, ავიღოთ ერთი ციკლი 1–დან 128–მდე, განვიხილოთ ციკლის ცვლადის

ორობითი ჩანაწერები და შევკრიბოთ იმ თანრიგების შესაბამისი რიცხვები, სადაც 1–იანი წერია.

მიღებული შედეგი შევადაროთ 25–ს. ასეთი ალგორითმით განხილული იქნება ქვესიმრავლეთა

ყველა შესაძლო ვარიანტი.

main () {

int i, j, digits[7], sum, sum25=0;

Page 85: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

85

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);

}

ამოცანა 95. ნათურების გადართვა - Switching Lights

USACO 2008 წლის ნოემბრის შეჯიბრი, ბრინჯაოს დივიზიონი

ფერმერ ჯონს სურს გონებამახვილი ძროხები ჰყავდეს, ამიტომ ცდილობს, რომ

ინტელექტუალური თამაშებით გაართოს ისინი. ერთ-ერთ ასეთ თამაშს წარმოადგენს ნათურათა

გრძელი მწკრივი ბოსელში. 1-დან N-მდე (2<=N<=500) გადანომრილი თითოეული ძროხის

თავზე განლაგებულია ფერადი ნათურა.

თავიდან ყველა ნათურა გამორთულია. ძროხებს აქვთ N ცალი ჩამრთველი ნათურების

სამართავად. i-ურ ჩამრთველზე ზემოქმედებისას i-ური ნათურა აინთება, თუ იგი მანამდე

გამორთული იყო და პირიქით, ჩაქრება, თუ მანამდე ჩართული იყო.

ძროხები კითხულობენ და თანმიმდევრობით ასრულებენ M (1<=M<=2,000) ცალ

ბრძანებას, რომელთაგან თითოეული აღნიშნულია 0-ით ან 1-ით(0 <= operation <= 1).

პირველი ოპერაცია (აღნიშნულია 0-ით) შეიცავს ორ მთელ რიცხვს: S_i და E_i

(1<=S_i<=E_i<= N). ისინი განსაზღვრავენ საწყის და საბოლოო ჩამრთველებს, რომლებზეც

უნდა მოხდეს ზემოქმედება.

მეორე ოპერაცია (აღნიშნულია 1-ით) ასევე შეიცავს ორ მთელ რიცხვს: S_i და E_i

(1<=S_i<=E_i<= N) და წარმოადგენს შეკითხვას, თუ რამდენი ნათურაა ანთებული მოცემულ

დიაპაზონში.

დაეხმარეთ ფერმერ ჯონს და დაწერეთ პროგრამა, რომელიც გამოითვლის სწორ პასუხებს

ყველა დასმულ კითხვაზე.

შესატანი მონაცემები: პირველ სტრიქონში ორი მთელი რიცხვი: N and M. მომდევნო M

სტრიქონიდან თითოეულში სამ-სამი მთელი რიცხვი: operation, S_i, and E_i.

გამოსატანი მონაცემები: შეკითხვათა რაოდენობის შესაბამისი სტრიქონებიდან

თითოეულში გამოიტანეთ თითო მთელი რიცხვი - პასუხი შეკითხვაზე.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 4 5

0 1 2

0 2 4

1 2 3

0 2 4

1 1 4

1

2

შეტანის განმარტება: გვაქვს 4 ნათურა და 5 ქმედება.

Page 86: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

86

ნათურები 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 ნათურა

ანალიზი. მოვახდინოთ პროცესის სიმულაცია და შემოვიღოთ 500-ელემენტიანი მასივი

ნათურების მდგომარეობათა დასაფიქსირებლად. 0-ებით აღვნიშნოთ ჩამქრალი, ხოლო 1-ებით

ანთებული მდგომარეობა. მდგომარეობათა ცვლილების სწრაფი განხორციელებისათვის

გამოვიყენოთ ბიტური ოპერაცია xor, რომლის შედეგების ცხრილი ქვემოთ არის მოცემული:

xor 0 1

0 0 1

1 1 0

#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;

}

}

}

Page 87: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

87

ფუნქციები

აქამდე ჩვენ ვწერდით პროგრამებს ერთიანი, ფუნქციონალურად უწყვეტი კოდით და

პროგრამა შედგებოდა მხოლოდ მთავარი main ფუნქციისაგან. მცირე ზომის პროგრამების

წერისას ეს პრობლემას არ ჰქმნის, მაგრამ თუ კოდის სიგრძე საკმაოდ დიდია, უმჯობესია ის

დავყოთ ცალკეულ, დამოუკიდებელ ნაწილებად და მთავარ პროგრამაში ფუნქციებად

წარმოვადგინოთ. პროგრამირების ასეთ სტილს „მოდულურ“ პროგრამირებას უწოდებენ, ხოლო

სხვადასხვა ენებში ფუნქციის ნაცვლად გამოიყენება ტერმინები „ქვეპროგრამა“, „პროცედურა“

და ა.შ. ფუნქციის ერთ–ერთ მთავარ ღირსებას წარმოადგენს ის მომენტი, რომ ერთხელ

შექმნილი ფუნქცია მრავალჯერადად შეიძლება გამოვიძახოთ პროგრამის სხვადასხვა

ადგილიდან. ეს საგრძნობლად ამცირებს პროგრამის კოდს და იოლად გასაგებს ხდის მას.

ზოგადად ფუნქციები შეიძლება ორ ჯგუფად: სტანდარტული და მომხმარებლის მიერ

შექმნილი. სტანდარტული ფუნქციების ჩამონათვალი წიგნს თან ერთვის თითოეული მათგანის

დანიშნულების აღწერით. სტანდარტულ ფუნქციას აუცილებლად უნდა ახლდეს შესაბამისი

include ფაილი.

მომხმარებლის (ანუ ჩვენს მიერ) შექმნილ ფუნქციებს აქვთ შემდეგი სახე:

ფუნქციის_ტიპი ფუნქციის_სახელი (ფუნქციის_პარამეტრები) { ფუნქციის_ტანი; } ფუნქციის_ტიპი აღნიშნავს ფუნქციის მიერ დასაბრუნებელი მნიშვნელობის ტიპს. თუ

ფუნქცია მნიშვნელობას არ აბრუნებს, მაშინ ის განუსაზღვრელი, ანუ void ტიპისაა. ფუნქციის

სახელის შერჩევისას იგივე წესები ვრცელდება, როგორც იდენტიფიკატორის სახელზე.

ფუნქციისათვის გადასაცემი პარამეტრების ჩამონათვალი აუცილებლად მრგვალ ფრჩხილებში

უნდა იყოს მოქცეული. პარამეტრები ერთმანეთისაგან მძიმით გამოიყოფიან. ფუნქციის ტანი

აუცილებლად ფიგურულ ფრჩხილებშია ჩასმული.

ფუნქციის შიგნით აღწერილ ცვლადებს ლოკალურ ცვლადებს უწოდებენ და ისინი

წყვეტენ ფუნქციონირებას ფუნქციის დამთავრებისთანავე. ამრიგად, სხვადასხვა ფუნქციაში

შეიძლება გამოვიყენოთ ერთი და იგივე სახელის მქონე ლოკალური ცვლადები და ეს არანაირ

დაბრკოლებას არ შექმნის პროგრამის მუშაობისას. ცვლადები, რომლებიც აღწერილნი არიან

ყველა ფუნქციის გარეთ (მათ შორის, main ფუნქციის გარეთაც), მოქმედებენ პროგრამის

ნებისმიერ ნაწილში და მათ გლობალურ ცვლადებს უწოდებენ.

Page 88: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

88

ამოცანა 96. ოთხი რიცხვი

(ხორვატიის ღია პირველობა ინფორმატიკაში, მესამე შეჯიბრი, 2007/08)

მირკომ ოთხი რიცხვისაგან არითმეტიკული პროგრესია შეადგინა. სხვაგვარად რომ

ვთქვათ, თუ ოთხ რიცხვს დავალაგებთ, განსხვავება მეზობელთა ნებისმიერ წყვილს შორის

ტოლია. როგორც ხშირად ხდება მირკომ ერთი რიცხვი დაკარგა, დანარჩენი სამის

თანმიმდევრობაც აერია. დაწერეთ პროგრამა, რომელიც მოცემული სამი რიცხვის მიხედვით,

იპოვის მეოთხეს.

შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია სამი რიცხვი –100–დან 100–მდე

დიაპაზონში. პასუხის არსებობა გარატირებულია. რამდენიმე პასუხის შემთხვევაში,

გამოიტანეთ ნებისმიერი.

გამოსატანი მონაცემები: ერთადერთ სტრიქონში ერთი მთელი რიცხვი – პროგრესიის

მეოთხე წევრი.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 4 6 8 10 10 1 4 7

#include <cstdio>

int abs( int a ) {

if( a < 0 ) return -a;

return a;

}

int min3( int a, int b, int c ) {

if( a < b )

if( a < c ) return a;

else return c;

else

if( b < c ) return b;

else return c;

}

int main( void ) {

int a1, a2, a3;

scanf( "%d%d%d", &a1, &a2, &a3 );

int a4 = min3( a1, a2, a3 );

int d = min3( abs(a1-a2), abs(a1-a3), abs(a2-a3) );

while( a4 == a1 || a4 == a2 || a4 == a3 ) a4 += d;

printf( "%d\n", a4 );

return 0;

}

ამოცანა 97. ჰამ–ჰამ

(ხორვატიის ღია პირველობა ინფორმატიკაში, მეოთხე შეჯიბრი, 2007/08)

მეზობელ სოფელში ფოსტალიონს, მერძევეს და მეეზოვეს ყოველ დილით ერთი და იგივე

თავსატეხი აქვთ: სახლი ნომერი 18. ამ სახლს ორი ვეება ნაგაზი იცავს, თუმცა ყველამ არ იცის,

რომ მათი ქცევა გარკვეულ კანონზომიერებას ექვემდებარება.

ახალი დღის დადგომის შემდეგ პირველი ნაგაზი აგრესიულია A წუთის განმავლობაში

და შემდეგ მშვიდადაა B წუთის განმავლობაში. მეორე ნაგაზისათვის იგივე პერიოდები

გრძელდება C წუთი და D წუთი. ორივე ძაღლისათვის ეს ფაზები რიგრიგობით ენაცვლებიან

ერთმანეთს. ფოსტალიონის, მერძევის და მეეზოვის მისვლის დროების მიხედვით გაარკვიეთ,

თუ რამდენი ნაგაზი შეუტევს თითოეულ მათგანს – ორი, ერთი თუ არცერთი.

Page 89: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

89

შესატანი მონაცემები: პირველ სტრიქონში მოცემულია ოთხი რიცხვი რიცხვი: A, B, C და

D. მეორე სტრიქონში მოცემულია სამი მთელი რიცხვი: P, M და G – წუთებში გამოსახული

დროის ის მომენტი, როცა სახლთან მივა შესაბამისად ფოსტალიონი, მერძევე და მეეზოვე.

მაგალითად P=3 ნიშნავს, რომ ფოსტალიონი მივიდა სახლთან დღის დაწყებიდან მესამე წუთზე.

ყველა რიცხვი მოთავსებულია 1–დან 999–მდე.

გამოსატანი მონაცემები: მონაცემები გამოიტანეთ სამ სტრიქონში. თითოეულ სტრიქონში

უნდა ეწეროს 'both', 'one' ან 'none', იმის მიხედვით თუ რამდენი ნაგაზი შეუტევს ფოსტალიონს,

მერძევეს და მეეზოვეს.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 2 2 3 3

1 3 4

both

one

none 2 3 4 5

4 9 5

one

none

none

#include <cstdio>

int f( int x, int a, int b ) {

return (x-1) % (a+b) < a;

}

void solve( int x, int a, int b, int c, int d ) {

if( f( x, a, b ) + f( x, c, d ) == 0 ) printf( "none\n" );

if( f( x, a, b ) + f( x, c, d ) == 1 ) printf( "one\n" );

if( f( x, a, b ) + f( x, c, d ) == 2 ) printf( "both\n" );

}

int main( void ) {

int A, B, C, D;

scanf( "%d%d%d%d", &A, &B, &C, &D );

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;

}

ამოცანა 98. რძე – Milk

USACO 2001 წლის ზამთრის შეჯიბრი, “ნარინჯისფერი” დივიზიონი

ფერმერ ჯონს რძის შესანახად აქვს სამნაირი ბიდონი A, B და C ლიტრი ტევადობით.

თითოეული A, B და C რიცხვებიდან მთელი რიცხვია 1–დან 20–მდე დიაპაზონში. თავიდან A

და B ბიდონები ცარიელია, ხოლო C ბიდონი – ცარიელი. ზოგჯერ ჯონი გადაასხამს ხოლმე

რძეს ერთი ბიდონიდან მეორეში, ვიდრე ეს უკანასკნელი არ აივსება, ან პირველი არ დაიცლება.

გადასხმის პროცესი ყოველთვის ბოლომდე სრულდება. ამასთან, რძის გადაქცევა არ შეიძლება.

დაწერეთ პროგრამა, რომელიც დაადგენს, რამდენი განსხვავებული რაოდენობის რძე

შეიძლება მიიღოს ჯონმა გადასხმებით C ბიდონში ისე, რომ A ბიდონი ამ დროს ცარიელი იყოს.

შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია სამი რიცხვი – A, B და C.

Page 90: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

90

გამოსატანი მონაცემები: ერთადერთ სტრიქონში გამოიტანეთ ყველა ის შესაძლო რიცხვი,

რომელიც შეიძლება მიიღოს ჯონმა გადასხმებით C ბიდონში ისე, რომ A ბიდონი ამ დროს

ცარიელი იყოს.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 8 9 10 1 2 8 9 10

int A, B, C;

char hit[21][21][21];

void visit (int a, int b, int c);

void visit (int a, int b, int c) {

if (hit[a][b][c]) return;

hit[a][b][c] = 1;

if (b + a <= A) visit (a + b, 0, c); else visit (A, a + b - A, c); if (c + a <= A) visit (a + c, 0, b); else visit (A, b, a + c - A); if (a + b <= B) visit (0, a + b, c); else visit (a + b - B, B, c); if (c + b <= B) visit (a, c + b, 0); else visit (a, B, b + c - B); if (a + c <= C) visit (0, b, a + c); else visit (a + c - C, b, C); if (b + c <= C) visit (a, 0, b + c); else visit (a, b + c - C, C); }

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;

}

Page 91: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

91

ამოცანა 99. ალმასისმაგვარი სიტყვები

(USACO, 2001 წლის ზამთარი, ”ნარინჯისფერი” დივიზიონი)

სიტყვას, რომელიც იწყება და მთავრდება ერთი და იგივე სიმბოლოთი უწოდებენ

ალმასისმაგვარს. მაგალითად ალმასისმაგვარია სიტყვა ”ENCODE”. ასეთი სიტყვებისათვის

გამოიყენება ალმასისმაგვარი ჩაწერა. მაგალითად:

E

N N

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]);

Page 92: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

92

if (i > 0) {

printblank (2*i-1);

printf("%c", word[i]);

}

printf("\n");

}

exit (0);

}

ამოცანა 100. RADAR Brands - რადარ ხარისხი[Traditional, 2006]

USACO 2005/06 წლის მარტის შეჯიბრი, “ბრინჯაოს” დივიზიონი

ფერმერი ჯონი ძროხებს ანიჭებს ხარისხს. ყოველი ძროხის ახირება არის

'RADAR' ხარისხი. რადარ ხარისხისად იწოდება ძროხა, რომლის ნომერი ორივე

მხრიდან ერთნაირად იკითხება (ანუ, ის არის პალინდრომული). ყოველ ძროხას უნდა

მისი შვილის ხარისხი იყოს "RADAR" სტილის. ამასთან ყოველ დედას უნდა მისი

შვილის ხარისხი მიღებული იყოს მისი საკუთარი არა-RADAR ტიპის ხარისხიდან

შემდეგი წესით:ერთხელ ან მეტჯერ კრებენ თავისი ხარისხის რიცხვსა და ამ რიცხვის

შებრუნებულს.ზოგჯერ (მაგალითად: 12 + 21 = 33) ეს წესი იძლევა შედეგს და

მიიღება მართლა RADAR პალინდრომი. ზოგჯერ კი პროცესი უნდა გამეორდეს

მრავალჯერ, მანამ, სანამ არ მიიღება ეს RADAR ხარისხი. მაგალითად ხარისხი '87'

საჭიროებს 4 ბიჯს რათა გადაიქცეს RADAR ხარისხად:

ხარისხი რევერსი ჯამი

ბიჯი 1: 87 + 78 = 165

ბიჯი 2: 165 + 561 = 726

ბიჯი 3: 726 + 627 = 1353

ბიჯი 4: 1353 + 3531 = 4884

მოცემულია დედის ხარისხი (დადებითი მთელი რიცხვი). იპოვე ბიჯების

რაოდენობა და RADAR ხარისხი, რომელიც მიიღება ზემოთ აღწერილი პროცედურის

შედეგად. გარანტირებულია, რომ პასუხი არ იქნება 2 მილიარდზე მეტი.

შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია ერთი მთელი რიცხვი – დედის

არა-RADAR-ული ხარისხი.

გამოსატანი მონაცემები: ერთადერთ სტრიქონში გამოიტანეთ ორი, ჰარით გაყოფილი

რიცხვი: ბიჯების რაოდენობა და მიღებული RADAR ხარისხი.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი

87 4 4884

ანალიზი. რადგან პასუხის არსებობა გარანტირებულია, მოვახდინოთ პროცესის სიმულაცია,

ხოლო რიცხვის შესაბრუნებლად შევქმნათ ფუნქცია. #include <stdio.h>

int reverse(int n) {

int rev;

for (rev = 0; n>0; n =n/ 10)

rev = 10*rev + (n%10);

return rev;

}

main () {

int n, steps = 0;

scanf("%d", &n);

for (steps = 0; n != reverse(n); steps++)

n = n + reverse(n);

printf("%d %d\n", steps, n);

}

Page 93: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

93

სტრიქონები

ტექსტური ინფორმაციის დასამუშავებლად С–ში ხშირად გამოიყენება სტრიქონული

მასივები, რომლებიც რეალურად ორგანზომილებიან სიმბოლურ მასივებს წარმოადგენენ. ამ

მასივის ერთი განზომილება წარმოადგენს სტრიქონების რაოდენობას, ხოლო მეორე –

სტრიქონებს შორის ყველაზე მაქსიმალურის სიგრძეს. მაგალითად შემდეგი ოპერატორი

აცხადებს 30 სტრიქონისაგან შედგენილ მასივს, რომლის მაქსიმალური სიგრძე 79 სიმბოლოა. char str_array[30][80];

ცალკეულ სტრიქონებზე მიმართვისათვის საჭიროა მივუთითოთ მხოლოდ მარცხენა

ინდექსი. მაგალითად: gets(str_array[2]);

კლავიატურიდან აკრეფილ თითოეულ სიმბოლოს გააჩნია რიცხვითი კოდი, რისთვისაც

არსებობს სპეციალური სტანდარტი ASCII (ინგლ. American Standard Code for Information

Interchange). ქვემოთ მოყვანილია სიმბოლოთა განაწილება რიცხვით კოდებზე

აღნიშნული სტანდარტის მიხედვით. .

32

33 !

34 "

35 #

36 $

37 %

38 &

39 '

40 (

41 )

42 *

43 +

44 ,

45 -

46 .

47 /

48 0

49 1

50 2

51 3

52 4

53 5

54 6

55 7

56 8

57 9

58 :

59 ;

60 <

61 =

62 >

63 ?

64 @

65 A

66 B

67 C

68 D

69 E

70 F

71 G

72 H

73 I

74 J

75 K

76 L

77 M

78 N

79 O

80 P

81 Q

82 R

83 S

84 T

85 U

86 V

87 W

88 X

89 Y

90 Z

91 [

92 \

93 ]

94 ^

95 _

96 `

97 a

98 b

99 c

100 d

101 e

102 f

103 g

104 h

105 i

106 j

107 k

108 l

109 m

110 n

111 o

112 p

113 q

114 r

115 s

116 t

117 u

118 v

119 w

120 x

121 y

122 z

123 {

124 |

125 }

126 ~

127

ტექსტური ინფორმაციის დასამუშავებლად სტრიქონული მასივებზე უფრო

მოსახერხებელი საშუალებაა string, რომლის ფუნქციონირებისათვის საჭიროა

ბიბლიოთეკა:

#include <string>

string ტიპის მონაცემებთან სამუშაოდ პროგრამის დასაწყისში საჭიროა მიუთითოთ

using namespace std;, ხოლო შესაბამისი ტიპის ცვლადის აღწერა ასე ჩაიწერება. string s;

მინიჭების ოპერატორის გამოყენებისას string ტიპის მონაცემი ორმაგ ბრჭყალებში

უნდა ჩაისვას: s="Hello";

string ტიპის მთავარი ღირსება მისი სტანდარტული ფუნქციებია, რომელიც

საშუალებას იძლევა მოხერხებულად დავამუშავოთ ტექსტური ინფორმაცია.

Page 94: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

94

• s.append(str) - s სტრიქონის ბოლოს ამატებს str სტრიქონს. შეგვიძლია გამოვიყენოთ

როგორც ცვლადისთვის s.append(ცვლადი), ასევე ტექსტისთვის s.append("ტექსტი");

• s.assign(str) – s–ს ენიშება str სტრიქონის მნიშვნელობა. იგივეა, რაც s=str;

• int i=s.end() - i ცვლადს ანიჭებს სტრიქონის ბოლო სიმბოლოს ინდექსს.

• s.clear() - ასუფთავებს სტრიქონს, ანუ შლის მასში ყველა სიმბოლოს.

• s.compare(str) – ადარებს s სტრიქონს str სტრიქონთან და აბრუნებს 0–ს იგივეობის

შემთხვევაში

• s.copy(str, n, k) - აკოპირებს s სტრიქონიდან str–ში n ცალ სიმბოლოს დაწყებული k

ინდექსიდან (ბოლო ორი პარამეტრი სავალდებულო არაა).

• bool b=s.empty() - თუ სტრიქონი ცარიელია, აბრუნებს true, თუ არა false

• s.erase(k, n) – შლის s სტრიქონში n ცალ სიმბოლოს დაწყებული k პოზიციიდან.

• s.find(str, k) - ეძებს s სტრიქონში str სტრიქონს დაწყებული k პოზიციიდან.

• s.insert(k,str, beg, count) - სვამს s სტრიქონში k პოზიციიდან str სტრიქონის count ცალ

სიმბოლოს დაწყებული beg პოზიციიდან

• int len=s.length() - ანიჭებს len–ს s სტრიქონის სიგრძეს.

• s.push_back(symbol) - ამატებს სიმბოლოს სტრიქონის ბოლოში

• s.replace(index, n,str) - იღებს n პირველ სიმბოლოს str–დან და ამ სიმბოლოებით ცვლის s

სტრიქონის სიმბოლოებს, დაწყებული index პოზიციიდან.

• str=s.substr(n,m) - აბრუნებს m ცალ სიმბოლოს დაწყებული n პოზიციიდან.

• s.swap(str) უცვლის ადგილებს s და str სტრიქონების მნიშვნელობებს.

• s.size() - აბრუნებს სტრიქონში სიმბოლოთა რაოდენობას.

ამოცანა 101. სიტყვის კაპიტალიზაცია

http://codeforces.ru/problemset/problem/281/A

კაპიტალიზაციას უწოდებენ სიტყვის ისეთ ჩაწერას, როცა სიტყვის პირველი სიმბოლო

წარმოადგენს მაღალი რეგისტრის სიმბოლოს (მთავრულს). თქვენი ამოცანაა გამოიტანოთ

მოცემული სიტყვის კაპიტალიზაცია. მიაქციეთ ყურადღება, რომ კაპიტალიზაციის დროს

სიტყვაში პირველი სიმბოლოს გარდა ყველა უცვლელად რჩება.

შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია ლათინური სიმბოლოებისაგან

შედგენილი სიტყვა, რომლის სიგრძეც არ აღემატება 1000 სიმბოლოს.

გამოსატანი მონაცემები: გამოიტანეთ სიტყვის კაპიტალიზაცია.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი

ApPLe ApPLe

konjac Konjac

ანალიზი. როგორც ზემოთ მოყვანილი ASCII ცხრილიდან ჩანს, დაბალი რეგისტრის

სიმბოლოთა ათობითი კოდები 97-დან იწყება, ხოლო განსხვავება მაღალი და დაბალი

რეგისტრის სიმბოლოებს შორის 32-ია. შევამოწმოთ სიტყვის პირველი სიმბოლოს ათობითი

კოდი და თუ ის 96-ზე მეტია, შევამციროთ 32-ით.

#include<iostream>

using namespace std;

string s;

main(){

cin>>s;

if(s[0]>96) s[0]-=32;

cout<<s;

}

Page 95: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

95

ამოცანა 102. ფეხბურთი

http://codeforces.ru/problemset/problem/43/A

ვასომ იპოვა ბერლანდიის 1910 წლის თასის გათამაშების ფინალური თამაშის ოქმი

ფეხბურთში. სამწუხაროდ, ოქმში არ ეწერა საბოლოო შედეგი, თუმცა იყო მატჩის

მიმდინარეობის აღწერა. აღწერა შედგება n ცალი სტრიქონისაგან, რომელთაგან თითოეულში

წერია იმ გუნდის სახელი, რომელმაც გოლი გაიტანა. დაწერეთ პროგრამა, რომელიც გაარკვევს

გამარჯვებული გუნდის სახელს. გარანტირებულია, რომ თამაში ფრედ არ დასრულებულა.

შესატანი მონაცემები: პირველ სტრიქონში მოცემულია ერთი მთელი რიცხვი

n (1≤n≤100) - სტრიქონების რაოდენობა ოქმში. თითოეულ სტრიქონში მოცემულია გოლის

გამტანის დასახელება, რომელიც წარმოადგენს ლათინური ანბანის ზედა რეგისტრის

სიმბოლოებისაგან შედგენილ არაცარიელ სიტყვას. გარანტირებულია, რომ ოქმში არ გვხვდება

ორზე მეტი დასახელების გუნდი.

გამოსატანი მონაცემები: ერთადერთ სტრიქონში გამოიტანეთ გამარჯვებული გუნდის

დასახელება. ფეხბურთში გამარჯვებულად ითვლება მეტი გოლის გამტანი გუნდი.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი

1

ABC

ABC

5

A

ABA

ABA

A

A

A

ანალიზი. რადგან თამაშში ერთი გოლი მაინც არის გასული, წავიკითხოთ პირველი

გოლის გამტანი გუნდის სახელი ციკლის გარეშე და ყველა დანარჩენი სტრიქონი მას

შევადაროთ. ამასთანავე, თუკი შევგვხდება პირველი სტრიქონისაგან განსხვავებული სახელი, ეს

იქნება მეორე გუნდის სახელი და ის ცალკე ცვლადში დავიმახსოვროთ.

#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; }

ამოცანა 103. პალინდრომი

(ამიერკავკასიის სტუდენტთა პირადი პირველობა, 2002 წელი)

პალინდრომი ეწოდება ისეთ სიტყვას, რომელიც ერთნაირად იკითხება წინიდან და

უკნიდან. მაგალითად, სიტყვა deed პალინდრომია, ხოლო სიტყვა read – არა. დაწერეთ

პროგრამა, რომელიც გაარკვევს, პალინდრომია თუ არა მოცემული სიტყვა.

Page 96: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

96

შესატანი მონაცემები: ლათინური მთავრული ასოებისაგან შედგენილი სიტყვა, რომლის

სიგრძეც არ აღემატება 254 სიმბოლოს.

გამოსატანი მონაცემები: Yes – თუ შემომავალი მონაცემი პალინდრომია და No –

წინააღმდეგ შემთხვევაში.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი

DEED Yes

READ No

ანალიზი. რაიმე d ცვლადს მივანიჭოთ 0 და ციკლში წყვილ-წყვილად შევადაროთ სიტყვის

ბოლოებიდან თანაბრად დაშორებული სიმბოლოები: პირველი – ბოლოს, მეორე – ბოლოსწინას

და ა.შ. თუკი ვიპოვით ერთ მაინც განსხვავებულ წყვილს, d-ს მივანიჭოთ 1 და ციკლი

შევწყვიტოთ. პასუხი გამოვიტანოთ d-ს მნიშვნელობის მიხედვით ციკლის შემდეგ.

#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";

}

ამოცანა 104. ათობითში გადაყვანა

დაწერეთ პროგრამა, რომელიც წაიკითხავს 0-ებისა და 1-ებისაგან შედგენილ სიმბოლოთა

ჯაჭვს და ეკრანზე გამოიტანს შესაბამისი რიცხვის ჩანაწერს ათობით სისტემაში.

შესატანი მონაცემები: 0–ებისა და 1–ებისაგან შედგენილი სტრიქონი, რომლის სიგრძეც

არ აღემატება 30 სიმბოლოს.

გამოსატანი მონაცემები: შემომავალი მონაცემის შესაბამისი ათობითი ჩანაწერი.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი

10011001 153

110 6

111001110100111 29607

ანალიზი. დავადგინოთ ორობითი ჩანაწერის სიგრძე და ციკლის საშუალებით

თანმიმდევრულად განვიხილოთ ყველა სიმბოლო მარჯვნიდან მარცხნივ. განხილვის

პარალელურად რაიმე ცვლადი ვზარდოთ 2-ჯერ ყოველი იტერაციის დროს. ამ ცვლადში

მივიღებთ 2-ის ხარისხებს და პასუხში დავამატებთ მხოლოდ მათ, რომლებიც 1-იანებს

შეესაბამება.

#include <iostream>

#include <string>

using namespace std;

int i,j=1,n,ans;

string s;

main () {

Page 97: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

97

cin>>s;

n=s.size();

for(i=n-1;i>=0;i--){

ans=ans+j*((int)s[i]-48); j=j*2;} cout<<ans;

}

ამოცანა 105. ძალიან გრძელი სიტყვები

http://codeforces.com/problemset/problem/71/A

ზოგიერთი სიტყვა (მაგალითად, «localization» ან «internationalization»)

იმდენად გრძელია, რომ მათი ხშირად გამოყენება წერის დროს ძალზე დამღლელია.

ჩავთვალოთ, რომ სიტყვა ძალიან გრძელია, თუ მისი სიგრძე მკაცრად მეტია 10

სიმბოლოზე. ძალიან გრძელი სიტყვები შეიძლება შევცვალოთ სპეციალური აბრევიატურით. ეს

აბრევიატურა ასე იქმნება: იწერება სიტყვის პირველი და ბოლო სიმბოლო, ხოლო მათ შორის

სიმბოლოების რაოდენობა პირველ და ბოლო სიმბოლოს შორის (ათობით სისტემაში და

წამყვანი ნულების გარეშე). მაგალითად, «localization» იწერება როგორც «l10n», ხოლო

«internationalization» როგორც – «i18n».

დაწერეთ პროგრამა, რომელიც მოახდენს სიტყვების აბრევიატურით შეცვლის

ავტომატიზაციას. ამასთან, ძალიან გრძელი სიტყვები უნდა შეიცვალონ აბრევიატურით, ხოლო

სიტყვები, რომლებიც არ არიან ძალიან გრძელები – არა.

შესატანი მონაცემები: პირველ სტრიქონში ერთი მთელი რიცხვი – n(1≤n≤100).

მომდევნო n სტრიქონიდან თითოეულში მცირე ლათინური სიმბოლოებით შედგენილი სიტყვა,

რომლის სიგრძე შეიძლება იყოს 1–დან 100 სიმბოლომდე.

გამოსატანი მონაცემები: გამოიტანეთ n სტრიქონი. i–ურ სტრიქონში უნდა გამოიტანოთ

i–ური სიტყვის გარდაქმნის შედეგი.

შესატანი მონაცემების მაგალითი გამოსატანი მონაცემი 4

word

localization

internationalization

pneumonoultramicroscopicsilicovolcanoconiosis

word

l10n

i18n

p43s

#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;}

}

Page 98: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

98

ამოცანა 106. დაზიანებული კლავიატურა

კომპიუტერის კლავიატურა იმგვარადაა დაზიანებული, რომ ზოგჯერ კლავიშზე ხელის

დაჭერისას ერთის ნაცლად რამდენიმე სიმბოლოს ბეჭდავს. ცნობილია, რომ ამ კლავიატურიდან

შეტანილ ტექსტში ერთმანეთის მეზობლად ერთნაირი სიმბოლოები არ გვხდება. დაწერეთ

პროგრამა, რომელიც შეასწორებს ტექსტს და წაშლის მასში ზედმეტ სიმბოლოებს.

შესატანი მონაცემები: ლათინური დაბალი რეგისტრის ასოებისაგან შედგენილი სიტყვა,

რომლის სიგრძეც არ აღემატება 250 სიმბოლოს.

გამოსატანი მონაცემები: შესწორებული ტექსტი.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი

kkkkeybbooooarrrdd keyboard

ანალიზი. ცხადია, რომ ზედმეტი სიმბოლოები უნდა წავშალოთ და ამისათვის

გამოვიყენოთ სტანდარტული ფუნქცია. შევნიშნოთ, რომ სიმბოლოთა წაშლა უფრო

მოსახერხებელია ციკლში მარჯვნიდან მარცხნივ მოძრაობისას, ვიდრე პირიქით. ამის მიზეზი

ის არის, რომ წაშლილი სიმბოლოს მარჯვნივ მდგომი სიმბოლოები პოზიციას (ინდექსს)

იცვლიან და არსებობს საფრთხე, რომ ზოგიერთი სიმბოლო განუხილველი დარჩეს.

#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-ზე.

გამოსატანი მონაცემები: ერთადერთ სტრიქონში გამოიტანეთ გაშიფრული შეტყობინება.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი

110111010001 1100

ანალიზი. წავიკითხოთ სტრიქონი სამ-სამ სიმბოლოდ და შევკრიბოთ მათი რიცხვითი

მნიშვნელობები. რადგან 0-ის რიცხვითი კოდი 48-ის ტოლია, ხოლო 1-ის კოდი - 49-ის, მათ

მნიშვნელობებს 48 უნდა გამოვაკლოთ. ყოველი სამეულისათვის შევამოწმოთ ციფრთა ჯამი.

თუკი ჯამი მეტია ან ტოლი 2-ის, გამოვიტანოთ 1, ხოლო თუ 2-ზე ნაკლებია – 0.

Page 99: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

99

#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; }

}

ამოცანა 108. HQ9+

http://codeforces.com/problemset/problem/133A

HQ9+ — სახუმარო პროგრამული ენაა, რომელიც შედგება მხოლოდ 4 ერთსიმბოლოიანი

ბრძანებისაგან:

• «H» ბეჭდავს «Hello, World!»;

• «Q» ბეჭდავს თავად პროგრამის კოდს;

• «9» ბეჭდავს სიმღერის ტექსტს «99 ბოთლი ლუდი»,

• «+» ერთით ზრდის შინაგანი მთვლელის მნიშვნელობას.

ბრძანებები «H» და «Q» აღიქმება მხოლოდ ზედა რეგისტრში. ყველა სიმბოლო, რომელიც

არ წარმოადგენს ბრძანებას, იგნორირდება.

თქვენ გეძლევათ HQ9+ ენაზე დაწერილი პროგრამა. დაადგინეთ, მოხდება თუ არა რაიმეს

ბეჭდვა მისი შესრულებისას.

შესატანი მონაცემები: ერთადერთი სტრიქონში მოცემულია p სტრიქონი, რომელიც

წარმოადგენს HQ9+ ენაზე დაწერილ პროგრამას და რომლის სიგრძეც არ აღემატება 100

სიმბოლოს. თითოეული სიმბოლოს ASCII-კოდი მოთავსებული იქნება 33–დან 126–მდე

ჩათვლით.

გამოსატანი მონაცემები: ერთადერთ სტრიქონში გამოიტანეთ სიტყვა «YES», თუ რაიმე

შეტყობინება იქნება დაბეჭდილი და სიტყვა «NO» – წინააღმდეგ შემთხვევაში.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი Hi! YES

Codeforces NO

განმარტება. პირველ მაგალითში არის მხოლოდ ერთი ბრძანება «H», რომელიც გამოიტანს

ბეჭდვაზე «Hello, World!». მეორე მაგალითში არცერთი სიმბოლო არ წარმოადგენს ბრძანებას.

ანალიზი. ციკლის საშუალებით წავიკითხოთ სიმბოლოები თანმიმდევრულად და თუ

შეგვხდება 'H', 'Q' ან '9', დავბეჭდოთ "YES" და დავასრულოთ პროგრამა. თუკი ციკლი

დამთავრდა, დაბეჭდოთ "NO".

#include<stdio.h>

int main(){

char k;

while((k=getchar())!='\n')

if(k=='H'||k=='Q'||k=='9'){printf("YES");return 0;}

printf("NO");

}

Page 100: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

100

ამოცანა 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

ანალიზი. ამოცანა იოლად იხსნება შემომავალი მონაცემის როგორც რიცხვად, ასევე

სტრიქონად წაკითხვისას. ამ უკანასკნელ შემთხვევაში უნდა დავადგინოთ რიცხვის სიგრძე.

შემდეგ სიგრძის 3-ზე გაყოფის ნაშთის მიხედვით დავსვათ მძიმეები. ყურადღება უნდა

მივაქციოთ, რომ ზედმეტი მძიმე არ დავსვათ რიცხვის დასაწყისში (,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;

}

ამოცანა 109. სიმბოლოთა წყვილის ამორჩევა

http://codeforces.com/problemset/problem/50B

მოცემულია სტრიქონი S, რომელიც შედგება N ცალი სიმბოლოსაგან. საჭიროა

მოიძებნოს ისეთი მთელი i და j რიცხვების დალაგებულ წყვილთა რაოდენობა, რომ:

1. 1 ≤ i, j ≤ N

2. S[i] = S[j], ანუ S სტრიქონის i-ური სიმბოლო ტოლია j-ური სიმბოლოსი.

შესატანი მონაცემები: ერთადერთი სტრიქონი შეიცავს S-ს, რომელიც შედგება ციფრებისა

და დაბალი რეგისტრის ლათინური ანბანის სიმბოლოებისაგან. გარანტირებულია, რომ S არ

არის ცარიელი და მისი სიგრძე არ აღემატება 105-ს.

გამოსატანი მონაცემები: ერთი მთელი რიცხვი – i და j რიცხვების წყვილთა რაოდენობა

ზემოთ მითითებული თვისებებით. (x, y) და (y, x) წყვილები განსხვავებულად ითვლება.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი great10 7

aaaaaaaaaa 100

Page 101: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

101

ანალიზი. დავადგინოთ სტრიქონის სიგრძე და ერთი ციკლის საშუალებით დავთვალოთ

მასში შემავალი თითოეული სიმბოლოს რაოდენობა. ამისათვის გამოვიყენოთ ის თვისება, რომ

ყოველ სიმბოლოს (მათ შორის ციფრებსაც) შეესაბამება ორიგინალური კოდი. სწორედ ამ კოდის

შესაბამის ინდექსზე ავჯამოთ სიმბოლოთა რაოდენობა. ამის შემდეგ, მეორე ციკლის

საშუალებით გამოვთვალოთ ამოცანის პასუხი.

#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);

}

ამოცანა 110. პეტრე და მატარებელი

http://codeforces.com/problemset/problem/8A

პეტრეს აინტერესებს მატარებლით მოგზაურობა. მისი ინტერესი იმდენად დიდია, რომ

გამუდმებით ეძინება. ერთხელ, პეტრე მატარებლით მგზავრობდა A ქალაქიდან B ქალაქისაკენ

და როგორც ყოველთვის, თვლემდა. გამოღვიძებისას მან შენიშნა, რომ ყოველ სადგურს ჰქონდა

გარკვეული ფერის ალამი. პეტრემ დაიწყო ფერთა მიმდევრობის დამახსოვრება, მაგრამ მალე მას

ისევ ჩაეძინა. ამჯერადაც მისი ძილი დიდხანს არ გაგრძელებულა და გაღვიძების შემდეგ მან

ისევ დაიწყო ფერთა მიმდევრობის დამახსოვრება. გარკვეული დროის შემდეგ მას კვლავ

დაიძინა და ეძინა მგზავრობის დამთავრებამდე. შინ დაბრუნების შემდეგ პეტრემ უამბო

მშობლებს ფერთა ორი მიმდევრობის შესახებ და ქაღალდზეც ჩამოწერა შესაბამისი ფერები.

მშობლებმა იციან, რომ პეტრეს ფანტაზიორობა უყვარს. ამიტომ გთხოვენ თქვენ A-დან B

სადგურამდე ალამთა ფერების მოცემული მიმდევრობის და პეტრეს მიერ დანახული ორი

მიმდევრობის საშუალებით დაადგინოთ, როდის დაინახა პეტრემ ეს მიმდევრობები: A

სადგურიდან B-სკენ მგზავრობისას, თუ პირიქით, B-დან A-სკენ მგზავრობისას.

მშობლებმა ალმების ფერები აღნიშნეს ლათინური დაბალი რეგისტრის ასოებით. ერთი და

იგივე ფერი ერთნაირი სიმბოლოებით არის აღნიშნული, სხვადასხვა ფერი - სხვადასხვათი.

შესატანი მონაცემები: მოცემულია სამი არაცარიელი სტრიქონი. პირველის სიგრძე არ

აღემატება 105-ს და აღწერს ალამთა ფერებს საშუალედო სადგურებზე A-დან B-მდე (თავად A და

B სადურებზე ალმები არ არის). B-დან A სადურისაკენ მოძრაობისას მატარებელი გაივლის

იგივე სადგურებს, ოღონდ შებრუნებული მიმდევრობით. მეორე სტრიქონში მოცემულია

მიმდევრობა, რომელიც პეტრემ ამოწერა სიფხიზლის პირველი პერიოდის დროს, ხოლო მესამე

სტრიქონში - სიფხიზლის მეორე პერიოდის დროს. თითოეული მიმდევრობა შედგენილია

ლათინური დაბალი რეგისტრის სიმბოლოებისაგან და სიგრძე არ აღემატება 100-ს. ყოველი

მიმდევრობა ჩაწერილია ქრონოლოგიური თანმიმდევრობით. მატარებელი გამუდმებით

მოძრაობს და ერთი და იგივე ალმის ორჯერ დანახვა შეუძლებელია. გამოსატანი მონაცემები: უნდა გამოიტანოთ 4-დან ერთ-ერთი სიტყვა:

• „forward“ - თუ პეტრეს ამ მიმდევრობის დანახვა შეეძლო A-დან B-სკენ გზაზე;

• „backward“ - თუ პეტრეს ამ მიმდევრობის დანახვა შეეძლო B-დან A-სკენ გზაზე;

• „both“ - თუ პეტრეს ამ მიმდევრობის დანახვა შეეძლო ორივე გზაზე;

• „fantasy“ - თუ პეტრეს ამ მიმდევრობის დანახვა არ შეეძლო.

Page 102: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

102

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი atob

a

b

forward

aaacaaa

aca

aa

both

#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;

}

Page 103: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

103

სორტირება. მინიმალური და მაქსიმალური

ამოცანა 111. ყანჩები

რუსეთის ოლიმპიადა, რეგიონული ეტაპი, 2012

პეტიამ და მაშამ ზოოპარკში გაისეირნეს. პეტიას ყველაზე მეტად ყანჩები

მოეწონა. ის აღფრთოვანდა ყანჩების უნარით – დაეძინათ ცალ ფეხზე მდგომებს.

ვოლიერში რამდენიმე ყანჩაა. ზოგი დგას ორ ფეხზე, ზოგი – ცალ ფეხზე. როცა

ყანჩა დგას ცალ ფეხზე, მეორე ფეხი არ ჩანს. პეტიამ დაითვალა ყველა ყანჩის ფეხები

(რომლებიც ჩანდა) და გამოვიდა a რაოდენობა. რამდენიმე წუთის შემდეგ ვოლიერთან მაშა

მივიდა. ამ დროში ზოგიერთ ყანჩას შეეძლო მდგომარეობის შეცვლა, ამიტომ პეტიამ სთხოვა,

ხელახლა დაეთვალა ფეხები. მაშამ მიიღო რიცხვი b.

ზოოპარკიდან გამოსული პეტია და მაშა დაინტერესდნენ, რამდენი ყანჩა იყო ვოლიერში.

ბავშვები მალე მიხვდნენ, რომ ამ რიცხვის ცალსახად განსაზღვრა ყოველთვის არ მოხერხდება.

ახლა მათ სურთ გაიგონ, რა მინიმალური და მაქსიმალური რაოდენობის ყანჩა შეიძლება

ყოფილიყო ვოლიერში. დაწერეთ პროგრამა, რომელიც მოცემული a და b რიცხვების მიხედვით

გაარკვევს ამ საკითხს.

შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია ორი მთელი რიცხვი – a და b (1≤a≤109, 1≤b≤109).

გამოსატანი მონაცემები: ერთადერთ სტრიქონში გამოიტანეთ ორი, ჰარით გაყოფილი

რიცხვი: ყანჩების შესაძლო მინიმალური და მაქსიმალური რაოდენობა ვოლიერში. პასუხის

არსებობა გარანტირებულია.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 3 4 2 3

განმარტება. მოყვანილ მაგალითში შესაძლებელია შემდეგი ვარიანტები:

1) ვოლიერში ორი ყანჩაა. როცა პეტიამ დათვალა ფეხები, ერთი მათგანი იდგა ორ ფეხზე,

ხოლო მეორე – ერთზე. როცა მაშამ დათვალა ფეხები, ორივენი ორ–ორ ფეხზე იდგნენ.

2) ვოლიერში სამი ყანჩაა. როცა პეტიამ დათვალა ფეხები, სამივე მათგანი ცალ ფეხზე

იდგა. როცა მაშამ დათვალა ფეხები, ერთი ორ ფეხზე იდგა და ორი – ცალ ფეხზე.

#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;

}

ამოცანა 112. გენერლის სტუმრობა

http://codeforces.com/problemset/problem/144/A

ყველაზე საიდუმლო სამხედრო ნაწილს გენერალი უნდა ესტუმროს. ამის გამო

პოლკოვნიკმა თავისი ჯარისკაცები მოედანზე ერთ მწკრივად დააწყო. სამხედროს წესდების

თანახმად ჯარისკაცები მწკრივში სიმაღლის არაზრდადობით უნდა იდგნენ, მაგრამ რადგან

მოსამზადებლად დრო არ დარჩა, ჯარისკაცები არეულად დადგნენ. გენერალს მხედველობის

პრობლემა აქვს და ამიტომ მწკრივს სწორად დალაგებულად მიიჩნევს, თუ მაქსიმალური

სიმაღლის ჯარისკაცი მწკრივის სათავეში დგას, ხოლო მინიმალურის სიმაღლის ჯარისკაცი –

მწკრივის ბოლოში. დანარჩენი ჯარისკაცების განლაგებას მნიშვნელობა არ აქვს (იმ

შემთხვევაშიც კი თუ მწკრივში რამდენიმე მაქსიმალური ან მინიმალური სიმაღლის ჯარისკაცი

Page 104: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

104

დგას). მთავარია პირველი და ბოლო ჯარისკაცების სიმაღლე. მაგალითად, გენერალი

(4,3,4,2,1,1) განლაგებას თვლის სწორად, ხოლო (4,3,1,2,2) განლაგებას — არა.

ერთ წამში პოლკოვნიკს შეუძლია ადგილები გააცვლევინოს მწკრივში მდგარ ნებისმიერ

ორ მეზობელ ჯარისკაცს. რა მინიმალური რაოდენობის წამი დასჭირდება ისეთი მწკრივის

მიღებას, რომელიც გენერალს მოეწონება.

შესატანი მონაცემები: პირველ სტრიქონში მოცემულია ერთი მთელი რიცხვი – n (2≤n≤100).

მეორე სტრიქონში მოცემულია n ცალი მთელი რიცხვი: a1,a2,...,an (1≤ai≤100) –

ჯარისკაცთა სიმაღლეები მწკრივის დასაწყისიდან ბოლოსაკენ. აუცილებელი არ არის

სიმაღლეები განსხვავდებოდნენ.

გამოსატანი მონაცემები: გამოიტანეთ ერთი მთელი რიცხვი – წამთა მინიმალური

რაოდენობა, რომელიც დასჭირდება პოლკოვნიკს, რომ მიღებული მწკრივი გენერალს

მოეწონოს.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 4

33 44 11 22 2

7

10 10 58 31 63 40 76

10

პირველ მაგალითში პოლკოვნიკმა ადგილები უნდა გაუცვალოს ჯერ პირველ და მეორე

ჯარისკაცებს და შემდეგ მესამე და მეოთხე ჯარისკაცებს. ამას დასჭირდება 2 წამი, მიღებული

მწკრივს კი ექნება სახე: (44, 33, 22, 11). მეორე მაგალითში გაცვლები უნდა

განხორციელდეს შემდეგი მიმდევრობით: 1. (10, 10, 58, 31, 63, 40, 76)

2. (10, 58, 10, 31, 63, 40, 76)

3. (10, 58, 10, 31, 63, 76, 40)

4. (10, 58, 10, 31, 76, 63, 40)

5. (10, 58, 31, 10, 76, 63, 40)

6. (10, 58, 31, 76, 10, 63, 40)

7. (10, 58, 31, 76, 63, 10, 40)

8. (10, 58, 76, 31, 63, 10, 40)

9. (10, 76, 58, 31, 63, 10, 40)

10. (76, 10, 58, 31, 63, 10, 40)

11. (76, 10, 58, 31, 63, 40, 10)

#include <iostream>

using namespace std;

int main(){

int i,n,o=0,k,b,m=101,a;

cin>>n;

for(i=0;i<n;i++)

{cin>>k;

if(k<=m){a=i;m=k;}

if(k>o){b=i;o=k;}}

n+=b-a-1;if(b>a)n--;

cout<<n;

return 0;

}

Page 105: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

105

ამოცანა 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).

გამოსატანი მონაცემები: გამოიტანეთ ერთი მთელი რიცხვი – ამოცანის პასუხი.

შესატანი მონაცემების მაგალითები 5

1 10

2 9

3 8

4 7

5 6

5

1 100

2 50

51 99

52 98

10 60

1

1 1000000000

შესაბამისი გამოსატანი მონაცემები 4 4 0

განმარტება. პირველ მაგალითში მეხუთე მოვლენას მოიცავს მეოთხე, მეოთხეს – მესამე,

მესამეს – მეორე და მეორეს – პირველი. მეორე მაგალითში ყველა მოვლენას პირველი მოიცავს.

#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;

}

Page 106: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

106

ამოცანა 114. არითმეტიკული პროგრესია

მოცემულია n მთელი რიცხვი. დაწერეთ პროგრამა, რომელიც განსაზღვრავს ადგენენ თუ

არა ისინი არითმეტიკულ პროგრესიას მათი რაიმე თანმიმდევრობით დალაგებისას.

შესატანი მონაცემები: პირველ სტრიქონში მოცემულია ერთი მთელი რიცხვი – n (1≤n≤105). მეორე სტრიქონში მოცემულია n ცალი მთელი რიცხვი 1..109 დიაპაზონიდან.

გამოსატანი მონაცემები: გამოიტანეთ სიტყვა YES, თუკი მოცემული რიცხვები რაიმე

თანმიმდევრობით ადგენენ არითმეტიკულ პროგრესიას. წინააღმდეგ შემთხვევაში გამოიტანეთ

სიტყვა NO.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 9

80 50 10 30 70 40 20 60 90 YES

9

80 50 10 30 70 43 20 60 90

NO

ამოცანა 115. სეირნობა წვიმის ქვეშ

http://codeforces.com/problemset/problem/144/C

ბერლანდიაში ოპოზიცია აპირებს მასობრივი სეირნობის მოწყობას. ბულვარი, სადაც

სეირნობა უნდა მოეწყოს, შედგება n ცალი, მწკრივად განლაგებული ფილისაგან. მსვლელობა

უნდა დაიწყოს 1 ფილიდან და დასრულდეს ფილაზე ნომრით n. სეირნობის დროს

ნებადართულია მეზობელ ფილაზე გადასვლა და ნაბიჯის გაკეთება ერთი ფილის

გამოტოვებით. უფრო ფორმალურად, i (i<n-1) ნომერი ფილიდან შეიძლება გადასვლა i+1 ან

i+2 ნომერ ფილებზე (n-1 ნომერი ფილიდან გადასვლა მხოლოდ n–ურზე შეიძლება).

გადასვლა ფილიდან ფილაზე შეიძლება ჩავთვალოთ მყისიერად.

ოპოზიციური აქციის ჩასაშლელად ბერლანდიის სისხლიანმა რეჟიმმა წვიმები გამოიწვია.

ფილები ბულვარში ცუდი ხარისხისაა და ისინი სწრაფად იშლებიან წვიმისაგან. ცნობილია, რომ

i-ური ფილა უვარგისი ხდება ai წვიმიანი დღის შემდეგ (ai–ურ დღეს ფილა ჯერ კიდევ

მთელია, ხოლო ai+1 დღეს – დაშლილი). დაშლილ ფილებზე სიარული კატეგორიულად

აკრძალულია! ამიტომ ოპოზიციური სეირნება ჩაშლილად ცხადდება, თუ დაშლილია ფილა

ნომერი 1, ან თუ დაშლილია ფილა ნომერი n, ან შეუძლებელია მივიდეთ პირველი ფილიდან

მე–n–ე ფილამდე მხოლოდ მთელი ფილებით.

ოპოზიციონერებს სურთ, რაც შეიძლება მეტი თანამოაზრე შეუერთდეს აქცია და

სჭირდებათ დაადგინონ, რამდენი დღის განმავლობაში იქნება შესაძლებელი სეირნობა

პირველი ფილიდან მე–n–ე ფილამდე.

შესატანი მონაცემები: პირველ სტრიქონში მოცემულია ერთი მთელი რიცხვი n (1≤n≤103)

– ბულვარის სიგრძე (ფილების რაოდენობით გამოსახული). მეორე სტრიქონში მოცემულია n

ცალი მთელი რიცხვი ai (1≤ai≤103) — დღეების რაოდენობა, რომლის შემდეგაც i-ური

ფილა დაიშლება.

გამოსატანი მონაცემები: ერთი მთელი რიცხვი – დღეების რაოდენობა, რომლის

განმავლობაშიც შეიძლება ბულვარში სეირნობა.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 4

10 3 5 10 5

5

10 2 8 3 5 5

Page 107: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

107

განმარტება. პირველ მაგალითში მესამე დღის შემდეგ დაიშლებაა მეორე ფილა, რის

შემდეგაც შესაძლებელი იქნება სეირნობა მარშრუტით 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; }

ამოცანა 116. თამაში ჯოხებით

http://codeforces.com/problemset/problem/451/A IOI 2014-ზე, აკშატმა და მალვიკამ გართობა გადაწყვიტეს. ამჟამად ისინი თამაშობენ

ბადით, რომელიც შედგენილი n ჰორიზონტალური და m ვერტიკალური ჯოხისაგან.

გადაკვეთის წერტილი ბადეზე ეწოდება ბადის ნებისმიერ წერტილს, რომელიც

წარმოიქმნება ერთი ჰორიზონტალური და ერთი ვერტიკალური ჯოხისაგან. ქვემოთ ნაჩვენები

ბადისათვის n = 3 და m = 3. ბადე შედგენილია n + m = 6 ჯოხისაგან. ბადეზე სულ არის n·m = 9

გადაკვეთის წერტილი, რომელიც გადანომრილია 1–დან 9–მდე.

თამაშის წესები მარტივია. მოთამაშეები სვლებს რიგრიგობით აკეთებენ. აკშატმა ოქროს

მედალი აიღო, ამიტომ პირველ სვლას ის აკეთებს. მოთამაშემ საკუთარ სვლაზე უნდა აირჩიოს

ნებისმიერი დარჩენილი გადაკვეთის წერტილი და შემდეგ აიღოს ბადის ორივე ჯოხი, რომელიც

ამ წერტილზე გადის. მოთამაშე აგებს, თუ იგი სვლას ვეღარ გააკეთებს (ანუ თუ ბადეზე აღარ

დარჩა გადაკვეთის წერტილი).

ვთქვათ, ორივე მოთამაშე ოპტიმალურად თამაშობს. ვინ მოიგებს?

შესატანი მონაცემები: ორი მთელი რიცხვი – n და m (1 ≤ n, m ≤ 100).

Page 108: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

108

გამოსატანი მონაცემები: გამოიტანეთ "Akshat" ან "Malvika" (ბრჭყალების გარეშე) იმისდა

მიხედვით, ვინ გაიმარჯვებს ოპტიმალური თამაშის შედეგად.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 2 2 Malvika 2 3 Malvika 3 3 Akshat

ამოცანა 117. პეტრე და სოფელი

http://codeforces.com/problemset/problem/66/B

პატარა პეტრე ხშირად სტუმრობს სოფელში ბებიას. ბებიას დიდი ბოსტანი აქვს,

რომელსაც თუ ზემოდან დავხედავთ, შეგვიძლია წარმოვიდგინოთ, როგორც 1×n ზომის n ცალ

თანაბარ კვადრატად დაყოფილი მართკუთხედი. ბოსტნის თავისებურებად შეგვიძლია

მივიჩნიოთ ის ფაქტი, რომ ყოველ კვადრატულ ნაკვეთს აქვს თავისი ფიქსირებული სიმაღლე

და თითოეული მათგანის თავზე თანამედროვე წყალგაყვანილობის სისტემის მიერ შეიძლება

შევქმნათ ხელოვნური წვიმა.

ხელოვნური წვიმის შექმნა ძვირი ჯდება, ამიტომ ჩვენ შემოვიფარგლებით მისი

გამოყენებით მხოლოდ ერთი კვადრატული ნაკვეთის თავზე. ამასთან, წვიმის მიწოდებისას

წყალი შეიძლება გადავიდეს მეზობელ კვადრატულ ნაკვეთებზე, თუკი მათი სიმაღლე არ

აღემატება მოცემული ნაკვეთის სიმაღლეს. მაგალითად, თუ ბოსტანი წარმოადგენს 1×5 ზომის

მართკუთხედს, სადაც ნაკვეთების სიმაღლეებია 4, 2, 3, 3, 2, მაშინ 3 სიმაღლის მქონე ნებისმიერი

ნაკვეთის თავზე ხელოვნური წვიმის შექმნისას წყალი გადაედინება ყველა ნაკვეთზე, გარდა 4

სიმაღლის მქონე ნაკვეთისა. ქვემოთ მოყვანილია შესაბამისი ნახაზი:

პეტრე გატაცებულია პროგრამირებით, ამიტომ მან გადაწყიტა მოძებნოს ნაკვეთი, რომლის

თავზეც ხელოვნური წვიმის შექმნით წყალი მოხვდება მაქსიმალური რაოდენობის ნაკვეთებში.

დაეხმარეთ მას.

შესატანი მონაცემების ფორმატი: პირველ სტრიქონში მოცემულია ერთი მთელი რიცხვი

n (1≤n≤1000) – კვადრატული ნაკვეთების რაოდენობა. მეორე სტრიქონში ჩაწერილია

თითო ჰარით გაყოფილი n ცალი მთელი რიცხვი – ნაკვეთთა სიმაღლეები. ყველა

რიცხვი შესატან მონაცემებში მოთავსებულია 1..1000 დიაპაზონში.

გამოსატანი მონაცემების ფორმატი: ერთ სტრიქონში გამოიტანეთ ერთი რიცხვი –

ნაკვეთთა მაქსიმალური რაოდენობა, რომლებშიც მოხვდება წყალი, თუკი ჩვენ შევქმნით

ხელოვნურ წვიმას ზუსტად ერთი ნაკვეთის თავზე.

Page 109: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

109

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 1

2 1

5

1 2 1 2 1 3

8

1 2 1 1 1 3 3 4 6

#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;

}

ამოცანა 118. რიცხვები

საქართველოს ოლიმპიადა ინფორმატიკაში, რეგიონული ტური, 2007–08

მოცემულია n რაოდენობის მთელი რიცხვი (n≤100000), რომელთაგან თითოეული

აბსოლუტური მნიშვნელობით არ აღემატება 2 მილიარდს. ყოველ ბიჯზე შეგვიძლია

დარჩენილი რიცხვებიდან ნებისმიერო ორი ამოვშალოთ და მათ მაგივრად ჩავწეროთ მათი

საშუალო არითმეტიკული.

საბოლოო მიზანია, რომ n–1 ბიჯის შემდეგ დარჩენილი ერთადერთი რიცხვი იყოს რაც

შეიძლება მინიმალური.

შესატანი მონაცემები: პირველ სტრიქონში წერია ერთადერთი მთელი რიცხვი n. მეორე

სტრიქონში წერია ერთმანეთისგან ჰარით გამოყოფილი n რაოდენობის მთელი რიცხვი.

გამოსატანი მონაცემები: ერთადერთ სტრიქონში უნდა ჩაწეროთ მინიმალური შესაძლო

პასუხის მთელი ნაწილი.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი

3

10 7 10

8

განმარტება. ჯერ სიიდან ამოვიღებთ ორ 10–იანს და მათ მაგივრად ჩავწერთ (10+10)/2=10,

ხოლო შემდეგ ამოვიღებთ 10–ს და 7–ს და მათ მაგივრად ჩავწერთ (10+7)/2=8.5 ; დაგვრჩა ერთი

რიცხვი 8.5, პასუხად კი ვიღებთ მის მთელ ნაწილს, ე.ი. 8–ს.

#include <cstdio>

#include <cstdlib>

#include <cmath>

Page 110: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

110

#include <algorithm>

using namespace std;

int n, a[100005];

double sol;

int main(void) {

int i;

scanf("%d", &n);

for(i = 0; i < n; i++) scanf("%d", &a[i]);

sort(a, a+n);

sol = a[n-1];

for(i = n-1; i >= 0; i--) sol = 0.5*(sol+a[i]);

printf("%d\n", (int)floor(sol));

exit(0);

}

ამოცანა 119. Costume Party [Neal Wu]

USACO 2007/08 წლის იანვრის შეჯიბრი, “ბრინჯაოს” დივიზიონი

ფერმერ ჯონს სურს ძროხები ბალ-მასკარადზე წაიყვანოს, მაგრამ სამწუხაროდ მას

მხოლოდ ერთი კოსტუმი აღმოაჩნდა. ეს კოსტუმი ზუსტად ერგება ორ ძროხას სიგრძით S

(1<=S<=1,000,000). ჯონს N (2<=N<=20,000) ცალი ძროხა ჰყავს, რომლებიც

გადანომრილი ჰყავს 1-დან N-მდე. i-ური ძროხის სიგრძეა L_i (1<=L_i<=1,000,000).

ორ ძროხას შეუძლია მოთავსდეს კოსტუმში, თუ მათი სიგრძეების ჯამის არ აღემატება

კოსტუმის სიგრძეს. ფერმერ ჯონს სურს დაადგინოს, ძროხების რამდენი განსხვავებული

წყვილი შეიძლება მოთავსდეს ამ კოსტუმში.

შესატანი მონაცემები: პირველ სტრიქონში წერია ორი მთელი რიცხვი N და S. მომდევნო

N სტრიქონიდან თითოეულში წერია თითო მთელი რიცხვი: L_i.

გამოსატანი მონაცემები: ერთადერთ სტრიქონში გამოიტანეთ ერთი მთელი რიცხვი -

ძროხების განსხვავებულ წყვილთა რაოდენობა, რომლებსაც შეუძლიათ მოთავსდნენ კოსტუმში.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 4 6

3

5

2

1

4

განმარტება. სულ შესაძლებელია 4 წყვილის შედგენა: 1 და 3, 1 და 4, 2 და 4, 3 და 4.

ანალიზი. ცხადია, სრული გადარჩევა არ იმუშავებს, რადგან 20000^2 ოპერაცია

დასჭირდება. დავასორტიროთ რიცხვები და შემოვიღოთ ორი მთვლელი (კოდში ისინი

აღნიშნული არიან low და hi). ერთმა იმოძრაოს მასივის სათავიდან ბოლოსაკენ, ხოლო

მეორემ – პირიქით, ვიდრე ერთმანეთს არ გაუტოლდებიან. ყოველ ბიჯზე შევამოწმოთ

აღემატება თუ არა მათი ჯამი შემომავალ სიდიდეს (კოსტუმის ზომას) და შესაბამისად

ვზარდოთ პასუხი. ქვემოთ მოყვანილია რობ კოლსტადის ამოხსნა:

#include <stdio.h>

#include <stdlib.h>

compare (int *a, int *b) { return *a - *b; }

main() {

Page 111: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

111

int n, s, l[20000], i, j, count;

scanf ("%d %d", &n, &s);

for (i = 0; i < n; i++) scanf ("%d", &l[i]);

count = 0;

qsort(l, n, sizeof (int), compare);

int low = 0, hi = n-1;

while (low < hi) {

/* how many cows can pair with l[low]? */

while (low < hi && l[low] + l[hi] > s)

hi--;

if (low < hi) count += hi-low;

low++;

}

printf ("%d\n", count);

}

ამოცანა 120. გამოკვლევა - Exploration [Jeffrey Wang, 2007]

2007/08 ნოემბერი ბრინჯაო

ბესი მოგზაურობს საინტერესო ლანდშაფტის მქონე გზაზე. თუ ამ გზას წარმოვიდგენთ

რიცხვით ღერძად, ბესი მოგზაურობას იწყებს x=0 წერტილში. ღერძზე მდებარეობს

N(1<=N<=50,000) "წარმტაცი ადგილი", რომლებიც განლაგებულნი არიან წერტილებში

X(1)..X(N) (-10,000<=X(i)<=10,000). ბესის სურს მოასწროს რაც შეიძლება ბევრი

„წარმტაცი ადგილის“ ნახვა მზის ჩასვლამდე, სანამდეც დარჩენილია

T(1<=T<=1,000,000,000) წუთი. მზის ჩასვლის მომენტში მოძრაობა წყდება. ბესის

მანძილის ერთეულის გასავლელად დროის 1 ერთეული სჭირდება.

ბესი „წარმტაც ადგილებს“ მოინახულებს გარკვეული თანმიმდევრობით. კერძოდ, ის

ყოველთვის მიემართება იმ ადგილისაკენ, რომელიც მას ჯერ არ უნახავს და რომელიც ყველაზე

ახლოსაა მის საწყის წერტილთან (x=0). მოხმარეთ ბესის, რათა მან დაადგინოს, რამდენი

„წარმტაცი ადგილის“ ნახვა შეუძლია მზის ჩასვლამდე. „წარმტაცი ადგილების“ არცერთი

წყვილი არ მდებარეობს ერთნაირ მანძილზე საწყისი წერტილიდან.

შესატანი მონაცემები: პირველ სტრიქონში წერია ორი მთელი რიცხვი T და N. მომდევნო

N სტრიქონიდან თითოეულში წერია თითო მთელი რიცხვი: X(i).

გამოსატანი მონაცემები: ერთადერთ სტრიქონში გამოიტანეთ ერთი მთელი რიცხვი -

რამდენი „წარმტაცი ადგილის“ ნახვა შეუძლია ბესის მზის ჩასვლამდე.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 25 5

10

-3

8

-7

1

4

განმარტება. ბესი მოინახულებს „წარმტაც ადგილებს“ შემდეგი თანმიმდევრობით:

1, -3, -7, 8 და ამაზე მას დაეხარჯება 24 წუთი. ის ვეღარ მოასწრებს მე-10 პოზიციაში

მისვლას, რადგან ამისთვის მას 26 წუთი დასჭირდებოდა.

Page 112: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

112

ანალიზი. რადგან ბესი ყოველთვის მიდის იმ ახალ წერტილში, რომელიც ყველაზე ახლოსაა

საწყის წერტილთან, დავასორტიროთ „წარმტაცი ადგილების“ კოორდინატების აბსოლუტური

მნიშვნელობები და განვიხილოთ ისინი თანმიმდევრულად.

#include <stdio.h>

#include <stdlib.h>

abs(i) { return i < 0 ? -i:i; }

int compare_abs(int *a, int *b) {

return abs(*a) - abs(*b);

}

int list[50000];

main() {

int T, N, i, j, bessloc, nvisit, timevisit;

scanf ("%d %d", &T, &N);

for (i = 0; i < N; i++)

scanf ("%d", &list[i]);

qsort (list, N, sizeof(int), compare_abs);

/* 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);

}

Page 113: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

113

სტრუქტურები

წინა თავებში განვიხილეთ მასივები, სადაც ელემენტებში ვინახავდით ერთი და იმავე

ტიპის ინფორმაციას. პრაქტიკაში ხშირია შემთხვევა, როცა აუცილებელია სხვადასხვა ტიპის

მონაცემთა დაჯგუფება. მაგალითად, ბანკის მეანაბრეთა მონაცემები: სახელი და გვარი (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];

მიმართვა სტრუქტურის ცალკეულ ელემენტებზე შეიძლება ასე განვახორციელოთ: people[0].year=1983;

people[i].money=3958.73;

struct–ის ერთგვარ გამარტივებულ სახედ შეგვიძლია განვიხილოთ კლასი pair (წყვილი),

რომელიც გვხვდება მხოლოდ С++–ის სტანდარტულ ბიბლიოთეკაში და არ ფუნქციონირებს

С–ში. მის გამოსაყენებლად საჭიროა ფაილში ჩავრთოთ ბიბლიოთეკა #include <algorithm>.

pair საშუალებას იძლევა ერთმანეთთან დავაკავშიროთ ორი ელემენტი, ამასთან ამ

ელემეტებისათვის სახელების დარქმევა საჭირო არ არის, რადგან მათ სტანდარტულად

განსაზღვრული აქვთ სახელები first და second. ჩვენ უნდა მივუთითოთ მხოლოდ იმ

ცვლადის ან მასივის სახელი, რომელსაც აქვს pair სტრუქტურა და იმ ორი ელემენტის

მონაცემთა ტიპი, რომლებიც წყვილში უნდა გაერთიანდნენ. მაგალითად, თუ ჩვენ გვინდა რომ

შევქმნათ 10–ელემენტიანი მასივი სახელად book, მთელი რიცხვისა და string ტიპის წყვილით,

ინსტრუქციას ექნება სახე: pair< int, string > book[10];

მიმართვა მასივის ცალკეულ ელემენტებზე მოხდება როგორც book[i].first და

book[i].second. მაგალითად, book[i].first=784; ან book[2].second=“Tarzan”;

pair სტრუქტურის მქონე მასივის სორტირება სტანდარტული sort() ბრძანების

გამოყენებით ჩვეულებრივი მასივის ანალოგიურად ხდება. ამ შემთხვევაში sort() ბრძანება

მასივს ალაგებს first ელემენტის მნიშვნელობების მიხედვით, ხოლო თუ ეს მნიშვნელობები

ტოლია, მაშინ second ელემენტების მიხედვით. struct–ის შემთხვევაში sort() ბრძანების მიერ

ელემენტების რიგითობას ყურადღება არ ექცევა და საჭირო ხდება სპეციალური ფუნქციის

დაწერა, რომელიც განსაზღვრავს ელემენტთა პრიორიტეტებს სორტირებისას.

Page 114: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

114

ამოცანა 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» – თუკი ვერ გადავა.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 2 2

1 99

100 0

YES

10 1

100 100

NO

ანალიზი. ეტაპის გავლის ნებისმიერ მომენტში კირიტო მოწინააღმდეგედ აირჩევს

ყველაზე ნაკლები ძალის მქონე დრაკონს (თუკი მისი დამარცხება არ შეუძლია, სხვებს

მითუმეტეს ვერ დაამარცხებს), ამიტომ დრაკონების მონაცემები ჩავწეროთ pair სტრუქტურის

მქონე მასივში და დავასორტიროთ. თანმიმდევრულად შევამოწმოთ first ველის მონაცემები და თუ

კირიტოს ძალა მათ აღემატება, კირიტოს ძალა გავზარდოთ second ველის მნიშვნელობით.

#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";

}

ამოცანა 122. გამარჯვებული

http://codeforces.com/problemset/problem/2/A

ბერლანდიაში პოპულარული ბანქოს თამაშის „ბერლოგინგის“ შემდეგი წესებით

ვლინდება: თუკი თამაშის დასრულების მომენტში მხოლოდ ერთ მოთამაშეს აქვს მაქსიმალური

რაოდენობის ქულები, ის ცხადდება გამარჯვებულად. სიტუაცია რთულდება, თუ ასეთი

Page 115: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

115

მოთამაშე რამდენიმეა. თამაში თითოეულ ფსონზე მოთამაშე იგებს ან აგებს ქულათა გარკვეულ

რაოდენობას. თამაში მსვლელობის ჩანაწერში ეს აღინიშნება ფორმატით «name score», სადაც

name ამ მოთამაშის სახელია, ხოლო score – მოთამაშის მიერ დაგროვებული ქულების

რაოდენობა. თუკი score უარყოფითი რიცხვია, ეს ნიშნავს რომ მოთამაშემ ამ ფსონზე წააგო. თუ

რამდენიმე მოთამაშე აგროვებს მაქსიმალურ ქულას (ვთქვათ, ეს ქულაა m), მაშინ

გამარჯვებულად ცხადდება ის მოთამაშე, რომელმაც პირველმა (ანუ ყველაზე ადრე) მოაგროვა

m ქულა. თამაშის დაწყების წინ თითოეულ მოთამაშეს 0 ქულა აქვს. გარანტირებულია, რომ

თამაშის დასრულების მომენტში ერთ მოთამაშეს მაინც აქვს დადებითი ქულა.

შესატანი მონაცემების ფორმატი: პირველ სტრიქონში მოცემულია ერთი მთელი რიცხვი

n (1≤n≤1000) – ნათამაშევ ფსონთა რაოდენობა. მომდევნო n სტრიქონიდან

თითოეულში ფსონთა შედგები ფორმატით „name score“ ქრონოლოგიური

მიმდევრობით, სადაც name არის ლათინური დაბალი რეგისტრის სიმბოლოებისაგან

შედგენილი სტრიქონი სიგრძით 1–დან 32–მდე, ხოლო score არის მთელი რიცხვი

–1000..1000 დიაპაზონიდან.

გამოსატანი მონაცემები: გამოიტანეთ „ბერლოგინგის“ გამარჯვებულის სახელი.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 3

mike 3

andrew 5

mike 2

andrew

3

andrew 3

andrew 2

mike 5

andrew

ანალიზი. ციკლის ერთი გავლით შეგვიძლია დავთვალოთ ყველა მოთამაშის მიერ

დაგროვებული ქულები და ვიპოვოთ მათ შორის მაქსიმალური. თუ რამდენიმე მაქსიმუმი

გვაქვს, მონაცემების კიდევ ერთხელ ციკლური გავლით ვიპოვით ვინ მოაგროვა m ან მეტი ქულა

პირველად. ამასთან, რიგში გასათვალისწინებელია, შემთხვევა, როცა რომელიმე მოთამაშემ

შეიძლება მოაგროვოს m ან მეტი ქულა, მაგრამ შემდეგ წააგოს და გამარჯვებული ვერ გახდეს.

#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)){

Page 116: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

116

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;

}

ამოცანა 123. არჩევნების დრო – Election Time [Jeffrey Wang]

USACO 2007/08 იანვრის შეჯიბრი, “ბრინჯაოს” დივიზიონი

ფერმერი ჯონის ტირანული მმართველობიდან გათავისუფლების შემდეგ ძროხები

პირველ არცევნებს მართავენ და ბესი პრეზიდენტობის ერთ–ერთი კანდიდატია. თუმცა ვიდრე

არჩევნები ჩატარდება, ბესის სურს გაიგოს, რომელ კანდიდატს აქვს უკეთესი შანსი.

არჩევნები ორ რაუნდად ტარდება. მეორე რაუნდში გადადის K (1<=K<=N) ძროხა,

რომლებმაც პირველ ტურში ყველაზე მეტი ხმის მიიღეს. მეორე ტურში ყველაზე მეტი ხმის

მიმღები ძროხა პრეზიდენტი ხდება.

ყოველი i–ური ძროხისათვის ცნობილია მის მიერ პირველ რაუნდში მიღებული A_i

(1<=A_i<=1,000,000,000) ხმა და მეორე რაუნდში (თუკი იქ გავიდა) მიღებული B_i

(1<=B_i<=1,000,000,000) ხმა. გაარკვიეთ, რომელი ძროხა მოიგებს არჩევნებს. ყველა A_i

და ყველა B_i განსხვავებულია.

შესატანი მონაცემები: პირველ სტრიქონში მოცემულია ორი მთელი N და K. მომდევნო N

სტრიქონიდან თითოეულში: i+1 სტრიქონი შეიცავს ორ მთელ რიცხვს – A_i და B_i. გამოსატანი მონაცემები: გამოიტანეთ ერთი მთელი რიცხვი – არჩევნებში გამარჯვებული

ძროხის ნომერი.

შემავალი მონაცემების მაგალითი შესაბამისი გამომავალი მონაცემი 5 3

3 10

9 2

5 6

8 4

6 5

5

Page 117: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

117

განმარტება. სულ 5 ძროხაა. მეორე რაუნდში გადის 3 – 2, 4 და 5 ნომერი ძროხები. მეორე

რაუნდში 5 ხმით გაიმარჯვებს მეხუთე ნომერი ძროხა.

ანალიზი. უბრალოდ უნდა შევასრულოთ ის პროცესი, რომელიც ამოცანის პირობაშია

მოცემული. შევქმნათ მასივი ისეთი სტრუქტურისათვის, რომელშიც ჩაიწერება თითოეული

ძროხის ორივე მონაცემი. დავასორტიროთ ეს მასივი პირველი მონაცემის მიხედვით და K

საუკეთესო (ანუ ყველაზე მეტი ხმის მქონე) დავასორტიროთ მეორე მონაცემის მიხედვით (ან

ვიპოვოთ მეორე მონაცემის მაქსიმუმი.

#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;

fscanf (fin, "%d %d", &n, &k);

for (i = 0; i < n; i++) {

fscanf (fin, "%d %d", &votes[i].a, &votes[i].b);

votes[i].cownum = i;

}

qsort(votes, n, sizeof (struct vote_f), comparea);

qsort(votes, k, sizeof (struct vote_f), compareb);

fprintf (fout, "%d\n", votes[0].cownum+1);

exit (0);

}

ამოცანა 124. ფოტოგრაფი http://codeforces.com/problemset/problem/203/C

ვალერი დიდხანს ოცნებობდა ფოტოგრაფობაზე და ამიტომ იყიდა ახალი ფოტოაპარატი.

მისთვის შეკვეთების რაოდენობა დღითი დღე იზრდებოდა და ერთ მშვენიერ დღეს მას

დასჭირდა პროგრამა, რომელიც გაარკვევს, თუ რა მაქსიმალური რაოდენობის ადამიანის

მომსახურება შეუძლია. ფოტოაპარატის მეხსიერება d მეგაბაიტია და მას შეუძლია გადაიღოს

მაღალი და დაბალი ხარისხის სურათები. დაბალი ხარისხის სურათი ფოტოაპარატში იკავებს a

მეგაბაიტ ინფორმაციას, ხოლო მაღალი ხარისხის – b მეგაბაიტს. i–ური კლიენტი ითხოვს, რომ

მისთვის xi ცალი დაბალი ხარისხის ფოტოგრაფია და yi ცალი მაღალი ხარისხის ფოტოგრაფია.

კლიენტი კმაყოფილია მხოლოდ მაშინ, თუ მისი შეკვეთა მთლიანად შესრულდა. ვალერის

სურს, რაც შეიძლება მეტი კლიენტი ჰყავდეს კმაყოფილი. დაბალი ხარისხის სურათის

შესანახავად ფოტოაპარატში თავისუფალი უნდა იყოს არანაკლებ a მეგაბაიტისა, ხოლო მაღალი

ხარისხის სურათის შესანახავად – არანაკლებ b მეგაბაიტისა. თავდაპირველად ფოტოაპარატის

მეხსიერება ცარიელია. ვალერი არ შლის ფოტოაპარატიდან არცერთ სურათს, ამიტომ მისი

მეხსიერება ნელ–ნელა ივსება.

Page 118: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

118

გამოთვალეთ, რა მაქსიმალური რაოდენობის კლიენტის მომსახურება შეუძლია ვალერის

და გამოიტანეთ ამ კლიენტების ნომრები.

შესატანი მონაცემები: პირველ სტრიქონში მოცემულია ორი მთელი რიცხვი: n და d

(1≤n≤105, 1≤d≤109) – კლიენტების რაოდენობა და ფოტოაპარატის მეხსიერების მოცულობა.

მეორე სტრიქონში მოცემულია ორი მთელი რიცხვი: a და b (1≤a≤b≤104) — შესაბამისად

დაბალი და მაღალი ხარისხის სურათის ზომა. მომდევნო სტრიქონიდან თითოეულში

აღწერილია შეკვეთები. i–ურ სტრიქონში მოცემულია ორი მთელი რიცხვი: xi და yi

(0≤xi,yi≤105) – i–ური კლიენტის მიერ შეკვეთილი დაბალი და მაღალი ხარისხის სურათების

რაოდენობა.

გამოსატანი მონაცემები: პირველ სტრიქონში სტრიქონში ამოცანის პასუხი – რა

მაქსიმალური რაოდენობის კლიენტის მომსახურება შეუძლია ვალერის. მეორე სტრიქონში

გამოიტანეთ ამ კლიენტების ნომრები. ყველა ნომერი განსხვავებული უნდა იყოს. თუ პასუხი

რამდენიმეა – გამოიტანეთ ნებისმიერი.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 3 10

2 3

1 4

2 1

1 0

2

3 2

3 6

6 6

1 1

1 0

1 0

1

2

ანალიზი. ცხადია, რომ ვალერი უფრო მეტ კლიენტს მოემსახურება, თუკი ამოარჩევს

ჯამურად ნაკლები მეხსიერების მომთხოვნ შეკვეთებს. ე.ი. ჩვენ უნდა დავთვალოთ თითოეული

კლიენტის სურათებისათვის საჭირო ჯამური მეხსიერება, დავალაგოთ ეს მონაცემი

ზრდადობით და თანმიმდევრობით შევასრულოთ შეკვეთები ვიდრე მეხსიერება გვეყოფა.

ერთადერთი პრობლემა აქ არის ის, რომ დალაგებისას დაიკარგება კლიენტთა თავდაპირველი

ნომრები. ეს რომ არ მოხდეს, გამოვიყენოთ 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;}}

Page 119: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

119

if(i==n) {cout<<i<<endl;}

for(i1=0;i1<i;i1++){

cout<<d[i1].second<<" ";}

}

ამოცანა 125. ისტორია

http://codeforces.com/problemset/problem/137/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). მოვლენები მოცემულია რაიმე კანონზომიერების გარეშე.

გამოსატანი მონაცემები: ერთადერთი რიცხვი – ამოცანის პასუხი.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი 5

1 10

2 9

3 8

4 7

5 6

4

5

1 100

2 50

51 99

52 98

10 60

4

1

1 1000000000

0

#include<stdio.h>

#include<algorithm>

using namespace std;

typedef struct area{

int d;

int f;

}saz;

saz z[100005];

bool mycompare(area v1, area

v2) {

return v1.d < v2.d;

}

int a,s,n,i,g,h,j,k,l;

#include<iostream>

#include<algorithm>

using namespace std;

int n,S,i;

pair<int,int> a[1005];

int main()

{cin>>S>>n;

for(i=1;i<=n;i++) cin>>a[i].first>>a[i].second;

sort(a+1,a+n+1);

for(i=1;i<=n;i++){

Page 120: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

120

main(){

scanf("%d",&n);

if(n==1) {printf("0");return 0;}

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);}

if(S<=a[i].first) {cout<<"NO"<<endl;return 0;} S+=a[i].second;}

cout<<"YES"<<endl;

}

Page 121: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

121

მიმთითებელი

ამოცანა 126. ორმაგი კოლა http://codeforces.com/problemset/problem/82/A

შელდონი, ლეონარდი, პენი, რაჯეში და ჰოვარდი ამ თანმიმდევრობით დგანან რიგში

სასმელ „Double Cola“–ს გასაყიდ ავტომატთან. მათ გარდა რიგში არავინ დგას. რიგში პირველი

(შელდონი) ყიდულობს ქილას, სვამს და ორმაგდება! ამის შემდეგ ორივე შელდონი დგებიან რიგის

ბოლოში. რიგში მომდევნო (ლეონარდი) ასევე ყიდულობს ქილას, ორმაგდება და დგება რიგში ორ

ეგზემპლარად და ა.შ. ეს პროცესი უსასრულოდ გრძელდება. მაგალითად, მას შემდეგ რაც პენიც

დალევს სასმელს, რიგს ექნება სახე: რაჯეში, ჰოვარდი, შელდონი, შელდონი, ლეონარდი,

ლეონარდი, პენი, პენი.

დაწერეთ პროგრამა, რომელიც გაარკვევს იმ ადამიანის სახელს, ვინც დალევს მე–n–ე ქილა

სასმელს.

შესატანი მონაცემები: ერთი მთელი რიცხვი n (1≤n≤109).

გამოსატანი მონაცემები: ერთადერთ სტრიქონში გამოიტანეთ ერთი სიტყვა – იმ ადამიანის

სახელი, ვინც დალევს მე–n–ე ქილა სასმელს. ქილები გადანომრილია 1–დან. მიაქციეთ ყურადღება

სახელების მართლწერას: "Sheldon", "Leonard", "Penny", "Rajesh", "Howard" (ბრჭყალების გარეშე).

თავიდან მეგობრები სწორედ ამ მიმდევრობით დგანან რიგში.

შესატანი მონაცემების მაგალითი შესაბამისი გამოსატანი მონაცემი

1 Sheldon

6 Sheldon 1802 Penny

#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;

}

Page 122: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

122

კომბინირებული ამოცანები

ამოცანა 127. რვაობითი

(ხორვატიის ღია პირველობა ინფორმატიკაში, 2007–08 წელი, მე–3 შეჯიბრი)

სლავკო სწავლობს თვლის სისტემებს და მან უნდა გადაიყვანოს ორობითი რიცხვები

რვაობითში. ალგორითმი, რომელსაც სლავკო იყენებს, ასეთია:

•მოცემული ორობითი რიცხვი შევავსოთ ნულებით მარცხნიდან ისე, რომ ციფრების

საერთო რაოდენობა 3–ის ჯერადი გახდეს;

•თანმიმდევრულად დავაჯგუფოთ ორობითი 3–წევრიან ჯგუფებად.

•ორობითი ჩანაწერის თითოეული ჯგუფი შევცვალოთ შევცვალოთ რვაობითი

რიცხვით მარჯვნივ მოცემული ცხრილის შესაბამისად.

დაწერეთ პროგრამა, რომელიც გარდაქმნის რიცხვის ორობით კოდს რვაობითად.

შესატანი მონაცემები: ერთადერთ სტრიქონში მოცემულია რიცხვის ორობითი ჩანაწერი. მასში

ციფრების რაოდენობა 100–ზე ნაკლებია და პირველი ციფრი 1–ის ტოლია.

გამოსატანი მონაცემები: მოცემული რიცხვის რვაობითი ჩანაწერი.

შესატანი მონაცემები მაგალითი შესაბამისი გამოსატანი მონაცემი 1010 12 11001100 314

#include <iostream>

#include <string>

using namespace std;

int main() {

string s;

cin >> s;

while( s.length() % 3 != 0 ) s = "0" + 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;

}

000 0

001 1

010 2

011 3

100 4

101 5

110 6

111 7

Page 123: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

123

ამოცანა 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.

ანალიზი. თუ განვიხილავთ დადებითი რიცხვების ორ ჯგუფს, რომელთა შორის უარყოფითი

რიცხვები დგას, იოლი მისახვედრია, რომ დადებითი რიცხვების ორივე ჯგუფის ერთიანად

განხილვას მხოლოდ მაშინ აქვს აზრი, თუკი ისინი ცალ-ცალკე აღემატებიან მათ შორის მყოფი

უარყოფითი რიცხვების ჯამის აბსოლუტურ მნიშვნელობას. შეტანის ნიმუშში სწორედ ასეთი

მაგალითია: -2-5=-7 აბსოლუტური მნიშვნელობით ნაკლებია 8-ზეც და 4+9=13-ზეც. თუკი შეტანის

ნიმუშს ასე გადავაკეთებთ: -3, 4, 9, -4, -5, 8, -3, მაშინ სამივე დადებითი რიცხვის ერთად განხილვას

აზრი აღარ აქვს და ამოცანის პასუხი 4+9=13 იქნება. ამ მსჯელობიდან გამომდინარე შეიძლება

ჩამოვაყალიბოთ შემდეგი ალგორითმი: რიცხვები თანმიმდევრულად შევკრიბოთ მანამ, ვიდრე

ჯამი დადებითი იქნება, ხოლო უარყოფითი ჯამის მიღების შემთხვევაში აჯამვა თავიდან

დავიწყოთ. გასათვალისწინებელია შემთხვევა, როცა ყველა შემომავალი რიცხვი უარყოფითია. ამ

დროს პასუხი 0-თან ყველაზე ახლოს მდგომი რიცხვია. რეალიზაციისათვის უმჯობესია

Page 124: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

124

შემოვიღოთ მეორე მასივი სადაც ჯამებს გენერაციას მოვახდენთ და ამოცანის პასუხი სწორედ ამ

მასივის მაქსიმუმი იქნება. ვნახოთ ამ მასივის შევსება შეტანის ნიმუშისათვის:

საწყისი მასივი -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);

}

Page 125: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

125

თვლის სისტემები. თვლის ორობითი სისტემა. კავშირი კომპიუტერის მეხსიერებაში ინფორმაციის

შენახვასა და ორობითი სისტემას შორის. ბიტი. ბაიტი.

თვლის სისტემა ეწოდება რიცხვთა ჩაწერის სიმბოლურ მეთოდს, რომელიც განსაზღვრავს

რიცხვთა წარმოდგენის წესებს. ადამიანს უძველესი დროიდან უწევდა სხვადასხვა საგნების

დათვლა. ამის გამო, სავარაუდოდ, თავდაპირველად თვლის უნარული სისტემა შეიქმნა, სადაც

რიცხვები აღინიშნებოდნენ შესაბამისი რაოდენობის ხაზებით.

ცხადია, რომ თვლის ასეთი სისტემა ფრიად მოუხერხებელია დიდი რიცხვების ჩასაწერად და

მათზე თუნდაც შეკრება-გამოკლების ოპერაციათა ჩასატარებლად, ამიტომ დროთა განმავლობაში

შეიქმნა სხვადასხვა სახის თვლის სისტემები, რომლებიც საბოლოო ჯამში, ორ ჯგუფად შეგვიძლია

დავყოთ: პოზიციური და არაპოზიციური.

თვლის არაპოზიციურ სისტემებში ციფრის წონა დამოკიდებული არაა მის პოზიციაზე.

თვლის ასეთი სისტემის ნიმუშია რომაული სისტემა. რომაულ სისტემაში ციფრებად გამოიყენება

შემდეგი სიმბოლოები: 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-ით

Page 126: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

126

და 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-მდე

თვლის ზოგიერთ სისტემაში. მარცხენა ნულები შეგვიძლია უგულვებელვყოთ.

ათობითი ორობითი სამობითი რვაობითი თექვსმეტობითი 1 00000001 00000001 00000001 1

2 00000010 00000002 00000002 2

3 00000011 00000010 00000003 3

4 00000100 00000011 00000004 4

5 00000101 00000012 00000005 5

6 00000110 00000020 00000006 6

7 00000111 00000021 00000007 7

8 00001000 00000022 00000010 8

9 00001001 00000100 00000011 9

10 00001010 00000101 00000012 A

11 00001011 00000102 00000013 B

12 00001100 00000110 00000014 C

13 00001101 00000111 00000015 D

14 00001110 00000112 00000016 E

15 00001111 00000120 00000017 F 16 00010000 00000121 00000020 10

17 00010001 00000122 00000021 11

Page 127: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

127

1. რიცხვების შეკრება-გამოკლება თვლის მოცემულ სისტემაში; რიცხვების გადაყვანა თვლის ერთი

სისტემიდან მეორეში.

არითმეტიკული ოპერაციები ორობითი, თექვსმეტობითი თუ სხვა ფუძის მქონე თვლის

სისტემებში ხორციელდება იმავე წესებით, როგორც ეს ათობით სისტემაში ხდება. განვიხილოთ ეს

ოპერაციები ცალ-ცალკე.

მოვიყვანოთ შეკრების ცხრილი ორობითი სისტემისათვის. ცხრილში რუხი ფერით

მონიშნული რიცხვების გადაკვეთაზე ჩაწერილია ამ ორი რიცხვის ჯამი.

0 1

0 0 1

1 1 10

შევკრიბოთ ორობითი რიცხვები 10011 და 1000111.

თანრიგები 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

Page 128: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

128

მაგალითისათვის შევკრიბოთ ორი თექვსმეტობითი რიცხვი 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

0 0 0

1 0 1

ამ ცხრილის გამოყენებით გადავამრავლოთ ორი რიცხვი 101011 და 1101 ისეთივე წესით,

როგორც ამას ათობით სისტემაში ვაკეთებთ:

1 0 1 0 1 1

* 1 1 0 1

1 0 1 0 1 1

1 0 1 0 1 1

1 0 1 0 1 1

1 0 0 0 1 0 1 1 1 1

ე.ი, 1010112*11012=10001011112, იგივე რიცხვები ათობითში: 4310*1310=55910.

გამრავლების ცხრილი თექვსმეტობითი სისტემისათვის:

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

Page 129: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

129

ამ ცხრილის გამოყენებით გადავამრავლოთ თექვსმეტობითი 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.

ინფორმატიკაში ხშირადაა საჭირო რიცხვის გადაყვანა თვლის ერთი სისტემიდან

მეორეში.რვაობითში ჩაწერილი რიცხვის ორობით სისტემაში გადასაყვანად საჭიროა, რომ

რვაობითის თითოეული ციფრი შევცვალოთ შესაბამისი ორობითი სამეულით (ტრიადით).

ცხადია, რომ საპირისპირო ამოცანის გადასაწყვეტად (ორობითიდან რვაობითში გადაყვანა)

ორობითის თანრიგები ასევე უნდა დავყოთ სამეულებად მარჯვნიდან მარცხნივ და ყოველი

სამეული უნდა შევცვალოთ შესაბამისი რვაობითი ციფრით. მაგალითად:

4578=100 101 1112

11 101 110 0012=35618

გადაყვანა ორობითიდან თექვსმეტობითში და პირიქით, ხდება რვაობითისა და ორობითის

ანალოგიურად, ოღონდ აქ სამეულების ნაცვლად ოთხეულები გამოიყენება.

ზოგადად ათობითიდან K (K>1) ფუძის მქონე თვლის სისტემაში მთელი რიცხვის

გადასაყვანად ასე უნდა მოვიქცეთ:

მოცემული რიცხვი გავყოთ K-ზე და ნაშთი ჩავიწეროთ. გაყოფის შედეგად მიღებული მთელი

ნაწილი ისევ გავყოთ K-ზე და ნაშთი ჩავწეროთ პირველი ციფრის მარცხნივ, შემდეგ მეორე

გაყოფისას მიღებული მთელი ნაწილი ისევ გავყოთ K-ზე და ა.შ. ვიდრე მთელი ნაწილი ნული არ

გახდება. ნაშთების მიმდევრობა (ჩაწერილი მარჯვნიდან მარცხნივ) წარმოადგენს მოცემული

რიცხვის K-ობით მნიშვნელობას.

განვიხილოთ მაგალითი. ვთქვათ, გვინდა 2305-ის გადაყვანა ათობითიდან შვიდობითში.

2305 : 7 = 329 (ნაშთი 2)

329 : 7 = 47 (ნაშთი 0)

47 : 7 = 6 (ნაშთი 5)

6 : 7 = 0 (ნაშთი 6)

ჩავწეროთ ნაშთების მიმდევრობა ბოლოდან პირველისაკენ. მივიღებთ 230510=65027.

თუკი რიცხვი გადასაყვანია შვიდობითიდან ათობითში, მაშინ ყველა ციფრი მარჯვნიდან მარცხნივ

უნდა გადავამრავლოთ 7-ის შესაბამის ხარისხზე (დაწყებული ნულოვანი ხარისხიდან) და

შევკრიბოთ: 65027=2*70+0*71+5*72+6*73=2+0+245+2058=230510.

Page 130: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

130

Page 131: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

131

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. ინგლისური ენის ასოები (მთავრული და პატარა ასოები განსხვავდებიან)

და ქვედა ხაზის სიმბოლო

A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

a b c d e f g h i j k l m n o p q r s t u v w x y z _

2. არაბული ციფრები

0 1 2 3 4 5 6 7 8 9

3. სპეციალური სიმბოლოები და არითმეტიკული ოპერაციების აღმნიშვნელი სიმბოლოები

, . ; : ? ' ! | / \ ~ * + – ) ( } { < > [ ] # % & ^ " და სხვა

4. გამყოფი და მმართველი სიმბოლოები

ესენია: ჰარი, ტაბულაციის სიმბოლოები, ახალ სტრიქონზე გადასვლის სიმბოლო და სხვა

5. ამას გარდა გამოიყენება ე.წ. მმართველი მიმდევრობები, ანუ სიმბოლოების სპეციალური

კომბინაციები. ზოგიერთი მათგანია: \b (ერთი პოზიციით დაბრუნება); \t (ჰორიზონტალური

ტაბულაცია); \n (ახალ სტრიქონზე გადასვლა); \0 (ნულოვანი სიმბოლო); \r (კურსორის გადატანა

სტრიქონის დასაწყისში) და სხვა.

Page 132: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

132

მუდმივა. ცვლადი. იდენტიფიკატორი.

პროგრამული მონაცემს (ან შეიძლება ითქვას, ობიექტს), რომელსაც მნიშვნელობა ენიჭება

პროგრამის შესრულების დაწყებამდე და შემდეგ, პროგრამის შესრულების დროს, ეს მნიშვნელობა

აღარ ეცვლება მუდმივას, ანუ კონსტანტას (constant) უწოდებენ. თუკი თავდაპირველად

მნიშვნელობა ეცვლება, მაშინ მონაცემს ცვლადი (variable) ეწოდება. ყოველ მუდმივას ან ცვლადს

უნდა ჰქონდეს სახელი, ანუ იდენტიფიკატორი, რომელიც შედგება ასოების, ციფრებისა და ქვედა

ხაზის სიმბოლოებისაგან. ამასთან, იდენტიფიკატორი უნდა იწყებოდეს ასოთი ან ქვედა ხაზის

სიმბოლოთი და არ უნდა იწყებოდეს ციფრით. ლათინური ანბანის მთავრული და პატარა ასოები

C-ში განსხვავდებიან (ზოგიერთი პროგრამული ენისაგან განსხვავებით). ამიტომ

იდენტიფიკატორები ab, Ab, aB და AB – 4 სხვადასხვა იდენტიფიკატორია. სწორი

იდენტიფიკატორების მაგალითებია: dkFG327, new_height, MaXiMuM, _raodenoba, ხოლო zurab.kar,

7ab, new height, – იდენტიფიკატორის არასწორი ჩაწერაა. იდენტიფიკატორის სიგრძეზე C++-ში

შეზღუდვა არ არის.

რეზერვირებული ან მომსახურე სიტყვები

ეს არის ის სიტყვები, რომლებიც გამოიყენება C-ს პროგრამაში. მაგალითად,

if for while double int struct else long switch continue

char return void case float sizeof break union do და სხვა.

ზოგიერთი რეზერვირებული სიტყვა იწყება ქვედა ხაზის სიმბოლოთი. მაგალითად, _far , _near,

_asm, და სხვა. პროგრამაში იდენტიფიკატორი არ უნდა ემთხვევოდეს რეზერვირებულ სიტყვებს.

კომენტარი C-ში

C-ზე დაწერილ პროგრამაში შეიძლება გამოვიყენოთ კომენტარი, რომელიც გააიოლებს

პროგრამის აღქმას არა მარტო სხვა პროგრამისტისათვის, არამედ თავად ავტორისათვისაც.

პროგრამის კომპილაციისას კომენტარს ყურადღება არ ექცევა, ამიტომ ის არანაირ გავლენას არ

ახდენს პროგრამის მუშაობაზე, თუკი, რა თქმა უნდა, წესების დაცვითაა მითითებული. კომენტარი

შესაძლოა ორნაირად გაკეთდეს: დაკომენტარდეს ტექსტი სტრიქონის რომელიმე პოზიციიდან

ამავე სტრიქონის ბოლომდე ან დაკომენტარდეს ტექსტის გარკვეული ბლოკი, რომელიც შეიძლება

მიმდევრობით განლაგებულ რამდენიმე სტრიქონსაც შეიცავდეს. პირველ შემთხვევაში

გამოიყენება ორი დახრილი ხაზი: //, ხოლო მეორე შემთხვევაში სიმბოლოები /* და */ . სადაც /*

კომბინაცია წარმოადგენს კომენტარის დასაწყისს, ხოლო */ – კომენტარის დასასრულს. კომენტარის

შიგნით კომენტარის აღმნიშნელი სიმბოლოების /* და */ გამოყენება აკრძალულია. მაგალითად,

სწორად ჩაწერილი კომენტარებია:

// S kvadratis fartobia. ან

/* S carmoadgens

kvadratis fartobs.*/

შემდეგი კომენტარები შეიცავენ შეცდომას:

/* P S kvadratis fartobia. ან

/* S carmoadgens */ kvadratis /* fartobs. */

Page 133: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

133

4. მონაცემთა საბაზო ტიპები. ტიპის მოდიფიკატორები. ცვლადების გამოცხადება, ინიციალიზება.

პროგრამირების ნებისმიერ ენაში, და მათ შორის C-შიც, ცვლადი წარმოადგენს ძირითად

სამუშაო ერთეულს, ოღონდ იგი მნიშვნელოვნად განსხვავდება იმ ცნებისაგან, რასაც მათემატიკურ

ცვლადში გულისხმობენ. მთავარი განსხვავება იმაში მდგომარეობს, რომ ცვლადს პროგრამირებაში

ყოველთვის ერთი კონკრეტული მნიშვნელობა აქვს მინიჭებული. კომპიუტერული ტერმინებით

რომ ვთქვათ, პროგრამირებაში ცვლადს მეხსიერების სახელდებულ უბანს, რომელშიც ინახება

გარკვეული მნიშვნელობა. ეს მნიშვნელობა შეიძლება შეიცვალოს პროგრამის მუშაობის დროს.

ყოველი ცვლადი C-ში უნდა იყოს გამოცხადებული (აღწერილი) მის გამოყენებამდე. ცვლადის

გამოცხადება გულისხმობს მისი იდენტიფიკატორისა და ტიპის მითითებას. გამოცხადების

ზოგადი ფორმა ასეთია:

ცვლადის ტიპი ცვლადთა სია;

C-ში განმარტებულია 5 საბაზო ტიპი:

char – სიმბოლური მონაცემი;

int – მთელი მონაცემი;

float – მოძრავმძიმიანი მონაცემი;

double – ორმაგი სიზუსტის მოძრავმძიმიანი მონაცემი;

void – ცარიელი სიდიდე (რომელსაც არა აქვს მნიშვნელობა).

გამოცხადების შემდეგ კომპიუტერის მეხსიერებაში ხდება იმ რაოდენობის ბაიტების

გამოყოფა, რამდენიც საჭიროა მითითებული ტიპის მონაცემის შესანახად. პროგრამის შესრულების

დროს ცვლადისათვის გამოყოფილი ადგილას მონაცემები შეიძლება მრავალჯერადად შეიცვალოს.

თუმცა დროის ნებისმიერ კონკრეტულ მომენტში ინახება ცვლადის მხოლოდ ერთი მნიშვნელობა -

რომელიც მას უკანასკნელად მიენიჭა. ცვლადის არცერთი წინა მნიშვნელობა მეხსიერებაში არ

ინახება. ცვლადის გამოცხადების მაგალითებია int x, c0, sum;

float av, mmk;

double month_balance, max, loss;

აქვე ხაზგასმით აღვნიშნოთ, რომ ცვლადის სახელი C-ში არასოდეს მიუთითებს მის ტიპს და

არანაირი შინაარსობრივი დატვირთვა არ ენიჭება კომპილატორისაგან.

ტიპები char და int მთელი ტიპებია. ისინი გამოიყენებიან მთელი რიცხვების შესანახად.

მართალია, char-ს ეწოდება სიმბოლური ტიპი, მაგრამ აქ წინააღმდეგობა არ არის. ცნობილია, რომ

ყოველი სიმბოლო დაკავშირებულია მთელ რიცხვთან – მის ორობით წარმოდგენასთან

კომპიუტერის მეხსიერებაში (კოდთან). სიმბოლური წარმოდგენა გვჭირდება, როდესაც

სიმბოლური ინფორმაცია შეგვაქვს კლავიატურიდან ან გამოგვაქვს ეკრანზე (ან პრინტერზე), ხოლო

კომპიუტერში სიმბოლოები შენახულია კოდებში. სიმბოლოს გარდაქმნა კოდში და პირიქით ხდება

ავტომატურად. char ტიპი იკავებს მეხსიერებაში 1 ბაიტს (8 ბიტს). თითოეული სიმბოლოს კოდი

მოყვანილია ცხრილში ASCII, რომელიც კოდების სტანდარტული ცხრილია და მოქმედებს მთელს

მსოფლიოში. მაგალითად, სიმბოლო-ციფრი ‘0’ წარმოდგენილია კომპიუტერში ორობითი

რიცხვით 00110000 , რაც შეესაბამება ათობით მნიშვნელობას 48, ე.ი. სიმბოლო ‘0’-ის კოდია 48

(ASCII ცხრილის მიხედვით). ტიპი char – ნიშნიანი ტიპია, მისი ცვლილების დიაპაზონია -128-დან

127-მდე.

ტიპი int იკავებს მეხსიერებაში 2 ბაიტს (16 ბიტს) ან 4 ბაიტს (32 ბიტს), რაც დამოკიდებულია

კომპიუტერის მანქანური სიტყვის სიგრძეზე (მანქანური სიტყვა არის ბიტების ერთობლიობა,

რომელსაც კომპიუტერი აღიქვამს როგორც ინფორმაციის ერთეულს და ამუშავებს ერთიანად): 16-

თანრიგიან მანქანებში int იკავებს 2 ბაიტს, 32-თანრიგიანში კი – 4 ბაიტს. ასე რომ, ერთი და იგივე

პროგრამა, რომლის მონაცემები მთელი ტიპისაა, შეიზლება სწორად მუშაობდეს ერთ

Page 134: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

134

კომპიუტერზე და არასწორად მეორეზე. იმისათვის, რომ მოიხსნას ეს უხერხულობა, C-ში

შემოღებულია მოდიფიკატორები long და short. short int ყოველთვის იკავებს 2 ბაიტს, long int – 4

ბაიტს.

ამას გარდა არსებობს კიდევ ორი მოდიფიკატორი: signed (ნიშნიანი) და unsigned (უნიშნო),

რომლებიც გამოიყენება int და char ტიპებთან. მაგალითად, signed short int აღწერს ნიშნიან მოკლე

მთელს, და მისთვის გამოიყოფა მეხსიერების 2 ბაიტი. ტიპები char, int, float და double გაჩუმების

პრინციპით არიან ნიშნიანები. ამიტომაც, წინა მაგალითში მოყვანილი ტიპის აღწერა შეიძლება

შევამოკლოთ: short int. მეტიც, ტიპი int იმდენად მნიშვნელოვანია, რომ ბოლო აღწერაში შეიძლება

გამოვტოვოთ int და ვწეროთ მარტო short.

signed long int არის ნიშნიანი გრძელი მთელი და მისთვის გამოიყოფა მეხსიერების 4 ბაიტი.

ესეთი ტიპის მონაცემი შეგვიძლია აგრეთვე აღვწეროთ როგორც long int ან long.

ნიშნიანი და უნიშნო მთელებს შორის განსხვავება დამოკიდებულია იმაზე, თუ როგორი

ინტერპრეტაცია აქვს მთელი რიცხვის უფროს ბიტს. მაგალითად, რიცხვი +3-ის წარმოდგენა

კომპიუტერის მეხსიერებაში შემდეგია:

0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1

მე-15

……. . . მე-4

მე-3

მე-2

1-

ლი

0-

ოვანი

ბიტი

მე-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 ბიტი.

Page 135: ზაზა გამეზარდაშვილი პროგრამირების საფუძვლები თეორია … · დავადგინოთ

135

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-მდე