Inzva Algorithm Programme 2018-2019 Bundle 1 Intro: Muhammed Burak Buğrul
Inzva Algorithm Programme 2018-2019 Bundle 1 Intro: Muhammed Burak Buğrul
Bundle 1
Intro
Editor
Muhammed Burak Buğrul
Reviewers
Kadir Emre Oto
Yusuf Hakan Kalaycı
1
Contents
1 Introduction 3
2 Command Line 3
2.1 Linux and Mac . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
4 Input/Output Redirection 4
4.1 Saving Output to a File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
4.2 Reading Input from a File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
4.3 Using Both at the Same Time . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
4.4 pipe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
4.5 diff . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
6 Big O Notation 7
7 Recursion 8
7.1 Time Complexity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
7.2 Mutual Recursion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
7.3 Enumeration and Brute-Force . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
9 Suggested Readings 17
9.1 C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
9.2 Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2
1 Introduction
First of all, this is an intensive algorithm programme prepared by inzva, which includes lectures,
contests, problem-solvings and a variety of practises. "Competitive Programming" term will be
mentioned frequently in this programme, especially for it’s community, help in progress in algorithms
and data structures etc.
Just for a quick cover up we will have a look at what happens when you compile and run a program,
basic data types and functions. After that, we will examine C++ Standard Template Library(STL),
time complexity and memory space.
2 Command Line
A lot of people don’t use command line if they can use an alternative. There are powerful IDEs
(Integrated Development Environments) and they really make programming easier in some aspects.
However, knowing how to use command line is important, especially for competitive programming.
Firstly, it gives a low level knowledge and full control; secondly, every computer and environment
has command line interface.
In this document, you will find only a basic introduction to the command line, which is no more than
the basic usage of a file system, compiler, and programs.
There are a lot of differences between command line of Windows and Linux. But the differences
between those of Mac and Linux are less.
Mac users can use the built-in Terminal. You can find it by searching from Spotlight. Linux users
can use gnome-terminal or any other installed one. Again, you can find them by using the built-in
search tab.
3
• rm - remove command. Usage: rm file_path
You can read more about the unix command line at:
http://linuxcommand.org
3.1 G++
G++ is installed in Linux environments but in Mac, you should install Xcode first.
You can compile your cpp souce file by typing g++ source.cpp. Default output of this command
is a.out.
For Linux and Mac, the command to run a program is ./program_name. If you use default g++
command, the name of your program will be a.out, so you should type ./a.out in order to run
it.
When you want to kill a program in running step, you can simply hit Control + C.
When you want to suspend a program in running step, you can simply hit Control + Z.
When you want to register EOF on standart input, you can simply hit Control + D.
4 Input/Output Redirection
You can redirect input and output streams of a program by using command line and it is surprisingly
easy.
The only thing you need is > symbol. Just add it at the end of your run command with the output
file name:
./a.out > output.txt
4
Note: This redirection process creates output.txt if it doesn’t exist; otherwise deletes all content in
it, then writes into it. If you want to use > in appending mode you should use » instead.
It is almost the same as output file redirection. The symbol is < now. Usage:
./a.out < input.txt
This will make your job easier than copying and pasting input to test your program,
especially in the contests.
One of the wonderful things about these redirections is that they can be used at the same time. You
can simply add both to the end of your run command:
./a.out < input.txt > output.txt
4.4 pipe
Sometimes, you may want to redirect the output of a program to another program as input. You
can use the | symbol for this. Usage:
./program1 | ./program2
4.5 diff
As the name denotes, it can check two files line by line if they are the same or not. If not, it outputs
different lines. Usage:
diff file1.txt file2.txt.
It is very useful for comparing output of brute force solution and real solution.
In almost every programming language, you can define your own data type. C++ has structs,
classes; Python has dictionaries, classes etc. You can think of them as packets that store more than
one different data and implement functions at the simplest level. They have a lot more abilities than
these two(You can check OOP out).
5
Let us examine a fraction struct written in C++.
1 struct Fraction {
2 int numerator, denominator;
3 };
This is the simplest definition of a struct. Fraction struct contains two int variables. We call them
members. So, Fraction struct has two members called numerator and denominator.
1 #include <cstdio>
2
3 struct Fraction {
4 int numerator, denominator;
5 };
6
7 Fraction bigFraction(Fraction a, Fraction b) {
8
9 if( a.numerator * b.denominator > a.denominator * b.numerator )
10 return a;
11
12 return b;
13 }
14
15 int main() {
16 // Create two Fractions in order to compare them
17 Fraction a, b;
18
19 a.numerator = 15;
20 a.denominator = 20;
21
22 b.numerator = 12;
23 b.denominator = 18;
24
25 // Create a new Fraction in order to store biggest of Fraction a and Fraction b.
26 fraction biggest = bigFraction(a, b);
27
28 printf("The biggest fraction is %d / %d\n", biggest.numerator, biggest.denominator);
29 return 0;
30 }
6
Let us do the same in Python3:
1 class Fraction:
2
In the sample codes above, a, b, and biggest are called objects of Fraction. Also, the word
instance can be used instead of object.
Sometimes, usage of struct can change in C++. When you have a pointer to a struct, you should
use -> to access its members instead of . operator. If you still want to use . operator, you should
do in this way: (*ptr).member. But arrow operator is simpler: ptr->member.
6 Big O Notation
When dealing with algorithms or coming up with a solution, we need to calculate how fast our algo-
rithm or solution is. We can calculate this in terms of number of operations. Big O notation moves
in exactly at this point. Big O notation gives an upper limit to these number of operations. The
formal definition of Big O is[1]:
Let f be a real or complex valued function and g a real valued function, both defined on some
unbounded subset of the real positive numbers, such that g(x) is strictly positive for all large enough
values of x. One writes:
If and only if for all sufficiently large values of x, the absolute value of f(x) is at most a positive
constant multiple of g(x). That is, f(x) = O(g(x)) if and only if there exists a positive real number
7
M and a real number x0 such that:
f (x) = O(g(x))
Almost every case for competitive programming, basic understanding of Big O notation is enough to
decide whether to implement a solution or not.
Note: Big O notation can be used for calculating both the run time complexity and the memory
space used.
7 Recursion
Recursion occurs when functions repeat themselves in order to create repeated applications or solve a
problem by handling smaller situations first. There are thousands of examples in mathematics. One
of the simple ones is factorial of n. It can be shown by n! in mathematics and it gives the product
of all positive integers from 1 to n, for example, 4! = 1 · 2 · 3 · 4 = 24. If we write factorial in a
mathematical way, it will be:
1 if n = 0
f (n) =
n · f (n − 1) if n > 0
The reason why we didn’t simply write it as f (n) = n · f (n − 1) is that it doesn’t give sufficient
information about function. We should know where to end the function calls, otherwise it can call
itself infinitely. Ending condition is n = 0 here. We call it base case. Every recursive function needs
at least one base case.
8
Basically, we can apply this recursive logic into programming:
3 int result = 1;
4
5 for( int i=1 ; i<=n ; i++)
6 res *= i;
7
8 return result;
9 }
We can say a function is a recursive if it calls itself. Let us change this iterative factorial function
into a recursive one. When you imagine how the recursive code will look like, you will notice it will
look like the mathematical one:
Note that we didn’t forget to put our base case into the recursive function implementation.
9
7.1 Time Complexity
In case above, it can be seen that both recursive and iterative implementations of factorial function
runs in O(n) time. But this equality doesn’t occur always. Let us examine fibonacci function, it is
mathematically defines as:
1 if n = 0 or n = 1
f (n) =
f (n − 1) + f (n − 2) if n > 1
Let us calculate time complexity of iterative one. There are three basic operations inside a for loop
that repeats n − 2 times. So time complexity is O(n). But what about the recursive one? Let us
examine its recursion tree(diagram of function calls) for n = 5 on visualgo.
f() function called more than one for some values of n. Actually in every level, number of function
calls doubles. So time complexity of the recursive implementation is O(2n ). It is far away worse than
the iterative one. Recursive one can be optimized by techniques like memoization, but it is another
topic to learn in further weeks.
10
7.2 Mutual Recursion
Mutual recursion occurs when functions call each other. For example function f calls another function
g, which also somehow calls f again.
Note: When using mutual recursions in C++, don’t forget to declare one of the functions so that
the other function can know first one from its’ prototype.
Note 2: You can chain more than two functions and it will be still a mutual recursion.
For example, permutation is one of enumeration techniques. First permutation of numbers in range
1 and n is:
1, 2, 3...n − 1, n
Additionally, we can try to enumerate all possible distributions of n elements into 3 different sets.
An example of a distribution of 5 elements can be represented as:
1, 1, 2, 1, 3
In this distribution the first, the second and the fourth elements goes into the first set; third element
goes into second set and the last element goes into the third set.
11
Enumerations can be done with recursive functions easily. We will provide example implementations
of 3-set one. But before examining recursive implementation, let us try to implement iterative one:
1 #include <cstdio>
2
3 int main(){
4
5 for( int i=1 ; i<=3 ; i++ )
6 for( int j=1 ; j<=3 ; j++ )
7 for( int k=1 ; k<=3 ; k++ )
8 for( int l=1 ; l<=3 ; l++ )
9 for( int m=1 ; m<=3 ; m++ )
10 printf("%d %d %d %d %d\n", i, j, k, l, m);
11
12 return 0;
13 }
It will print all possible distributions of 5 elements into 3 sets. But what if we had 6 elements? Yes,
we should have added another for loop. What if we had n elements? We can not add infinite number
of for loops. But we can apply same logic with recursive functions easily:
1 #include <cstdio>
2
3 int ar[100];
4
5 void enumerate( int element, int n ){
6
7 if( element > n ){ // Base case
8
9 for( int i=1 ; i<=n ; i++ )
10 printf("%d ", ar[i]);
11
12 printf("\n");
13 return;
14 }
15
16 for( int i=1 ; i<=3 ; i++ ){
17 ar[element] = i;
18 enumerate(element + 1, n);
19 }
20 }
21
22 int main(){
23 enumerate(1, 5);
24 return 0;
25 }
12
Brute-Force is trying all cases in order to achieve something(searching best, shortest, cheapest etc.).
One of the simplest examples of brute-forces approaches is primality checking. We know that for a
prime P there is no positive integer in range [2, P − 1] that evenly divides P . We can simply check
all integers in this range to decide if it is prime:
7 return true;
8 }
It is a simple function, but its’ time complexity is O(N ). Instead we can benefit from the fact if
there is a positive integer x that evenly divides N , there is a positive integer Nx as well. As we know
√
this fact, we can only check the integer in range [2, N ]:
√
Now, its’ time complexity is O( N ). It is far away better than O(N ).
13
8 Built-In Data Structures and Functions
There is no need to reinvent the wheel. Every language has its’ own built in data structures, functions
etc. After this point, the document will be C++ centered. But Python alternatives will be given.
The STL is a well known library for C++ that includes variety of data structures and algorithms.
8.2 Pairs
C++: Sometimes you may need to store two elements for an object. We can do this by creating
a struct/class or two dimensional array. They will all work well but using pairs will be much more
easier. You can think of pair as a class that has two variables named first and second. That’s all
for the basic. The good part is, you can decide their types(int, double, your own struct/class etc.).
An example for pairs in C++:
1 #include <iostream>
2
3 using namespace std;
4
5 int main(){
6
7 pair<int, int> p(1, 2);
8 pair<int, string> p2;
9
10 p2.first = 3;
11 p2.second = "Hey there!";
12
13 pair<pair<int, string>, string> nested;
14
15 nested.first = p2;
16 nested.second = "This is a nested one";
17
18 cout « "Info of p -> " « p.first « " " « p.second « endl;
19 cout « "Info of p2 -> " « p2.first « " " « p2.second « endl;
20 cout « "Info of nested -> " « nested.first.first « " " « nested.first.second
21 « " " « nested.second « endl;
22
23 return 0;
24 }
14
Python: You can simply create a tuple or an array:
1 p = (1, 2)
2 p2 = [1, "Hey there!"]
3 nested = ((3, "inner?"), "outer", "this is a tuple you can add more")
4
5 p2[0] = 3
6 # nested[0] = "don't" # In python you can't change tuples, but you can change arrays
7
8 print(p, p2, nested)
8.3 Vectors
C++: When using array, we should decide its size. What if we don’t have to do this, what if we
could add elements into it without considering the current size? Well, all these ideas take us to
vectors.
C++ has this structure. Its name is vector. It is a dynamic array but you don’t have to think about
its size. You can simply add elements into it. Like pairs, you can use it with any type (int, double,
another vector, your struct/class etc.). Usage of a vector is very similar to classic array:
1 #include <iostream>
2 #include <vector>
3
16 cout « endl;
17 return 0;
18 }
15
Python: Python lists already behave like vectors:
1 ar = []
2
3 for i in range(10):
4 ar.append(i)
5
6 print(ar)
C++: They are no different than stack, queue and deque we already know. It provides the imple-
mentation, you can simply include the libraries and use them. See queue, stack, deque
It is basically a built-in heap structure. You can add an element in O(logN ) time, get the first item
in O(logN ) time. The first item will be decided according to your choice of priority. This priority
can be magnitude of value, enterence time etc.
C++: The different thing for priority queue is you should add #include <queue>, not <priority_queue
>. You can find samples here. Again, you can define a priority queue with any type you want.
Note: Default priority_queue prioritizes elements by highest value first. Here is three ways of
defining priority.
C++: Now that we mentioned binary trees (heap above), we can continue on built-in self balanced
binary trees. Sets are key collections, and maps are key-value collections. Sets are useful when you
want to add/remove elements in O(logN ) time and also check existence of an item(key) in O(logN )
time. Maps basically do the same but you can change value associated to a key without changing the
position of the key in the tree. You can check c++ references for set and map. You can define them
with any type you want. If you want to use them with your own struct/class, you must implement
a compare function.
Python: You can use dictionaries for map and sets for set in python without importing any other
libraries.
16
8.7 Iterators
C++: You can use iterators for every built-in data structure in C++ for pointing their objects.
Python: You can iterate through any iterable in python by using in. You can check this example.
8.8 Sorting
C++: In almost every language, there is a built-in sort function. C++ has one as well. It runs in
O(N logN ) time. You can pass your own compare function into sort function of C++.
Python: You can use .sort() function for any list or list like collection in order to sort them or if
you don’t want to change the original collection, you can use sorted() function instead. You can pass
your own compare function into sort function of python by using key variable.
9 Suggested Readings
9.1 C++
• next_permutation: Link.
• binary_search: Link.
• upper_bound: Link.
• lower_bound: Link.
• reverse: Link.
• fill: Link.
• count: Link.
9.2 Python
• bisect: Link.
• collections: Link.
17
• built-in functions: Link.
• lambda: Link.
References
[1] Landau, Edmund (1909). Handbuch der Lehre von der Verteilung der Primzahlen [Handbook on
the theory of the distribution of the primes] (in German). Leipzig: B. G. Teubner. p. 31.
18