Arefin Art of Programming Contest
Arefin Art of Programming Contest
Reviewed By
Steven Halim
School of Computing, National University of Singapore
Singapore.
Foreworded By
ISBN 984-32-3382-4
DEDICATED TO
Shahriar Manzoor
Judge ACM/ICPC World Finals 2003-2006
(Whose mails, posts and problems are invaluable to all programmers)
And
ACKNOWLEDGEMENTS
I would like to thank following people for supporting me and helping me for the significant
improvement of my humble works. Infact, this list is still incomplete.
Professor Miguel A. Revilla
Dr. M Kaykobad
Dr. M. Zafar Iqbal
Dr. M. Lutfar Rahman
Dr. Abu Taher
Howard Cheng
Steven Halim
Shahriar Manzoor
Carlos Marcelino Casas Cuadrado
Mahbub Murshed Suman
Salahuddin Mohammad Masum
Samiran Mahmud
M H Rasel
Sadiq M. Alam
Mehedi Bakht
Ahsan Raja Chowdhury
Mohammad Rubaiyat Ferdous Jewel
KM Hasan
Monirul Islam Sharif
Gahangir Hossain
S.M Saif Shams
Shah Md. Shamsul Alam
Foreword Note
As the main resposible of the University of Valladolid Online Judge I has the feeling that this
book is not only a recollection of tutorials as the author says in the preface, but also will be an
essential part of the help sections of the UVa site, as it put together a lot of scattered
information of the Online Judge, that may help to many programmers around the world,
mainly to the newcomers, what is very important for us. The author proves a special interest
in guiding the reader, and his tips must be considered almost as orders, as they are a result of
a great experience as solver of problems as well as a problemsetter. Of course, the book is
much more that an Online Judge user manual and contains very important information
missing in our web, as the very interesting clasification of a lot of problems by categories,
that analyze in detail and with examples. I think it is a book all our users should be allowed to
access to, as is a perfect complement to our Online Judge.
Miguel A. Revilla
ACM-ICPC International Steering Committee Member and Problem Archivist
University of Valladolid, Spain.
http://acmicpc-live-archive.uva.es
http://online-judge.uva.es
Review Note
A Computer programming contest is a pleasurable event for the budding programmers, but
only a few books are available as a training manual for programming competitions.
This book is designed to serve as a textbook for an algorithm course focusing on
programming as well as a programming course focusing on algorithms. The book is specially
designed to train students to participate in competitions such as the ACM International
Collegiate Programming Contest.
The book covers several important topics related to the development of programming skills
such as, fundamental concepts of contest, game plan for a contest, essential data structures for
contest, Input/output techniques, brute force method, mathematics, sorting, searching, greedy
algorithms, dynamic programming, graphs, computational geometry, Valladolid Online Judge
problem category, selected ACM programming problems, common codes/routines for
programming, Standard Template Library (STL), PC2 contest administration and team
guide.The book also lists some important websites/books for ACM/ICPC Programmers.
I believe that the book will be book will be of immense use for young programmers interested
in taking part in programming competitions.
University of Dhaka.
Bangladesh.
Steven Halim
Contents
Chapter 1
Chapter 2
Chapter 3
Chapter 4
Chapter 5
Chapter 6
Chapter 7
Chapter 8
Chapter 9
Chapter 10
Chapter 11
Chapter 12
Chapter 13
Chapter 14
Appendix A
Appendix B
Appendix C
Appendix D
Appendix E
Fundamental Concepts
Game Plan For a Contest
Programming In C: a Tutorial
Essential Data Structures for Contest
Input/Output Techniques
Brute Force Method
Mathematics
Sorting
Searching
Greedy Algorithms
Dynamic Programming
Graphs
Computational Geometry
Valladolid OJ Problem Category
ACM Programming Problems
Common Codes/Routines For Programming
Standard Template Library (STL)
PC2 Contest Administration And Team Guide
Important Websites/Books for ACM
Programmers
14
19
27
72
81
85
91
106
113
117
121
134
172
174
176
188
230
235
242
CHAPTER 1
FUNDAMENTAL CONCEPTS
14
But while sending to online judges remove the two lines with freopen to avoid restricted
function errors. If you use the first freopen above, it will cause your program to take
input from the file FILE_NAME_FOR_INPUT. Write down the inputs in the file to
avoid entering input several times for debugging. It saves a lot of time. But as the
function opens input file which can be a cause of hacking the websites of online judges
they dont allow using the function and if you use it they will give compilation error
(Restricted Function). The second freopen is for generating the output of your program in
a specified file named FILE_NAME_FOR_OUTPUT on the machine. It is very
helpful when the output cant be justified just viewing the output window (Especially for
String Manipulation Problem where even a single space character can be a cause of
CHAPTER 1
FUNDAMENTAL CONCEPTS
15
Wrong answer). To learn about the function more check Microsoft Developer Network
(MSDN Collection) and C programming helps.
Programming languages and dirty debugging
Most of the time a beginner faces this problem of deciding which programming language
to be used to solve the problems. So, sometimes he uses such a programming language
which he doesnt know deeply. That is why; he debugs for finding the faults for hour
after hour and at last can understand that his problem is not in the algorithm, rather it is
in the code written in that particular language. To avoid this, try to learn only one
programming language very deeply and then to explore other flexible programming
languages. The most commonly used languages are C, C++, PASCAL and JAVA. Java is
the least used programming language among the other languages. Avoid dirty debugging.
Avoid Compilation Errors
The most common reply to the beginner from 24 hours online judge is COMPILATION
ERROR (CE). The advices are,
1) When you use a function check the help and see whether it is available in Standard
Form of the language. For example, do not use strrev function of string.h header file of C
and C++ as it is not ANSI C, C++ standard. You should make the function manually if
you need it. Code manually or avoid those functions that are available in your particular
compiler but not in Standard Form of the languages.
2) Dont use input and output file for your program. Take all the inputs for standard input
and write all the outputs on standard output (normally on the console window). Check
my previous topics.
3) Do not use conio.h header file in C or C++ as it is not available in Standard C and
C++. Usually dont use any functions available in <conio.h> header file. It is the great
cause of Compilation Error for the programmers that use Turbo C++ type compiler.
4) built-in functions and packages are not allowed for using in online judge.
5) Dont mail your program i.e. dont use yahoo, hotmail etc. for sending your program
to judge as it is a complex methodwrite judge id, problems number etc. Rather use
submit-system of the online judge for example, Submit page of Valladolid. Using the
former will give you CE most of the time as they include there advertisements at the
beginning and end of your program. So the judge cant recognize the extra characters
concatenated in your sent code and gives you CE. About 90% CE we ever got is for this
CHAPTER 1
FUNDAMENTAL CONCEPTS
16
reason. The mail system also breaks your programs into several lines causing Wrong
Answer or Other Errors though your program was correct indeed.
There are many famous online judges that can judge your solution codes 24 hours. Some
of them are:
Valladolid OJ (http://acm.uva.es/p)
Ural OJ (http://acm.timus.ru)
Saratov OJ (http://acm.sgu.ru)
ZJU OJ (http://acm.zju.edu.cn)
Official ACM Live Archive (http://cii-judge.baylor.edu/)
Peking University Online Judge (http://acm.pku.edu.cn/JudgeOnline/)
Programming Challenges (http://www.programming-challenges.com)
Sometimes, you may notice that many programmers solved many problems but they
made very few submissions (they are geniuses!). At first, you may think that I should try
to solve the problems as less try as possible. So, after solving a problem, you will not
want to try it again with other algorithm (may be far far better than the previous
algorithm you used to solve that problem) to update your rank in the rank lists. But my
opinion is that if you think so you are in a wrong track. You should try other ways as in
that and only that way you can know that which of the algorithms is better. Again in that
way you will be able to know about various errors than can occur. If you dont submit,
you cant know it. Perhaps a problem that you solved may be solved with less time in
other way. So, my opinion is to try all the ways you know. In a word, if you are a
beginner forget about efficiency.
Find the easier problems.Those problems are called ADHOC problems. You can find the
list of those problems available in 24 OJ in S. Halims, acmbeginners, acmsolvers
websites. Try to solve these problems and in that way you can increase your
programming capability.
Learn algorithms
CHAPTER 1
FUNDAMENTAL CONCEPTS
17
algorithms are described in Pseudocode). If you can write it without any errors, try to
find the problems related to the algorithm, try to solve them. There are many famous
books of algorithms. Try to make modified algorithm from the given algorithms in the
book to solve the problems.
Use simple algorithms, that are guaranteed to solve the problem in question, even if they
are not the optimum or the most elegant solution. Use them even if they are the most
stupid solution, provided they work and they are not exponential. You are not competing
for algorithm elegance or efficiency. You just need a correct algorithm, and you need it
now. The simplest the algorithm, the more the chances are that you will code it correctly
with your first shot at it.
This is the most important tip to follow in a programming contest. You dont have the
time to design complex algorithms once you have an algorithm that will do your job.
Judging on the size of your input you can implement the stupidest of algorithms and have
a working solution in no time. Dont underestimate todays CPUs. A for loop of 10
million repetitions will execute in no time. And even if it takes 2 or 3 seconds you
neednt bother. You just want a program that will finish in a couple of seconds. Usually
the timeout for solutions is set to 30 seconds or more. Experience shows that if your
algorithm takes more than 10 seconds to finish then it is probably exponential and you
should do something better.
Obviously this tip should not be followed when writing critical code that needs to be as
optimized as possible. However in my few years of experience we have only come to
meet such critical code in device drivers. We are talking about routines that will execute
thousands of time per second. In such a case every instruction counts. Otherwise it is not
worth the while spending 5 hours for a 50% improvement on a routine that takes 10
milliseconds to complete and is called whenever the user presses a button. Nobody will
ever notice the difference. Only you will know.
Simple Coding
1. Avoid the usage of the ++ or -- operators inside expressions or function calls. Always
use them in a separate instruction. If you do this there is no chance that you introduce an
error due to post-increment or pre-increment. Remember it makes no difference to the
output code produced.
2. Avoid expressions of the form *p++.
3. Avoid pointer arithmetic. Instead of (p+5) use p[5].
4. Never code like :
CHAPTER 1
18
FUNDAMENTAL CONCEPTS
return (x*y)+Func(t)/(1-s);
but like :
temp = func(t);
RetVal = (x*y) + temp/(1-s);
return RetVal;
This way you can check with your debugger what was the return value of Func(t) and
what will be the return code of your function.
5. Avoid using the = operator. Instead of :
return (((x*8-111)%7)>5) ? y : 8-x;
Rather use :
Temp = ((x*8-111)%7);
return 8-x;
If you follow those rules then you eliminate all chances for trivial errors, and if you need
to debug the code it will be much easier to do so.
NAMING 1 : Dont use small and similar names for your variables. If you have three
pointer variables dont name them p1, p2 and p3. Use descriptive names. Remember that
your task is to write code that when you read it it says what it does. Using names like
Index, RightMost, and Retries is much better than i, rm and rt. The time you waste by the
extra typing is nothing compared to the gain of having a code that speaks for itself.
NAMING 2 : Use hungarian naming, but to a certain extent. Even if you oppose it
(which, whether you like it or not, is a sign of immaturity) it is of immense help.
NAMING 3 : Dont use names like {i,j,k} for loop control variables. Use {I,K,M}. It
is very easy to mistake a j for an i when you read code or copy, paste & change code,
but there is no chance that you mistake I for K or M.
Last words
Practice makes a man perfect. So, try to solve more and more problems. A genius cant
be built in a day. It is you who may be one of the first ten of the rank lists after someday.
So, get a pc, install a programming language and start solving problem at once.[1]
CHAPTER 2
19
CHAPTER 2
20
In programming contests, you will be dealing with a set of problems, not only one
problem. The ability to quickly identify problems into the above mentioned contestclassifications (haven't see, have seen, have solved) will be one of key factor to do well in
programming contests.
Mathematics
Dynmic Programming
Graph
Sorting
Searching
Simulation
String Processing
Computational Geometry
AdHoc
Prime Number
Big Integer
Permutation
Number Theory
Factorial
Fibonacci
Sequences
Modulus
Longest Common Subsequence
Longest Increasing Subsequence
Edit Distance
0/1 Knapsack
Coin Change
Matrix Chain Multiplication
Max Interval Sum
Traversal
Flood Fill
Floyed Warshal
MST
Max Bipertite Matching
Network Flow
Aritculation Point
Bubble Sort
Quick Sort
Merge Sort (DAndC)
Selection Sort
Radix Sort
Bucket Sort
Complete Search, Brute Force
Binary Search (DAndC)
BST
Josephus
String Matching
Pattern Matching
Convex Hull
Trivial Problems
CHAPTER 2
21
Sometimes, the algorithm may be 'nested' inside a loop of another algorithm. Such as
binary search inside a DP algorithm, making the problem type identification not so trivial.
If you want to be able to compete well in programming contests, you must be able to
know all that we listed above, with some precautions to ad-hoc problems.
'Ad Hoc' problems are those whose algorithms do not fall into standard categories with
well-studied solutions. Each Ad Hoc problem is different... No specific or general
techniques exist to solve them. This makes the problems the 'fun' ones (and sometimes
frustrating), since each one presents a new challenge.
The solutions might require a novel data structure or an unusual set of loops or
conditionals. Sometimes they require special combinations that are rare or at least rarely
encountered. It usually requires careful problem description reading and usually yield to
an attack that revolves around carefully sequencing the instructions given in the problem.
Ad Hoc problems can still require reasonable optimizations and at least a degree of
analysis that enables one to avoid loops nested five deep, for example.
Ability to analyze your algorithm
You have identified your problem. You think you know how to solve it. The question that
you must ask now is simple: Given the maximum input bound (usually given in problem
description), can my algorithm, with the complexity that I can compute, pass the time
limit given in the programming contest.
Usually, there are more than one way to solve a problem. However, some of them may be
incorrect and some of them is not fast enough. However, the rule of thumb is:
Brainstorm many possible algorithms - then pick the stupidest that works!
Things to learn in algorithm
CHAPTER 2
22
Time (ms)
O(1)
1000
O(log n)
O(n)
1000
1000
9.96
1000
O(n log n)
1000
9960
O(n^2)
1000
1000000
O(n^3)
1000
10^9
O(2^n)
1000
2^1000
O(n!)
1000
uncountable
Comment
Excellent, almost impossible for most
cases
Very good, example: Binary Search
Normal, Linear time algorithm
Average, this is usually found in
sorting algorithm such as Quick sort
Slow
Slow, btw, All Pairs Shortest Paths
algorithm: Floyd Warshall, is O(N^3)
Poor, exponential growth... try to
avoid this. Use Dynamic
Programming if you can.
Typical NP-Complete problems.
Table 2: Limit of maximum input size under 60 seconds time limit (with
assumptions)
Order of Growth
O(1)
O(log n)
O(n)
Time (ms)
60.000 ms
60.000 ms
60.000 ms
Max Possible n
Virtually infinite
6^18.000
60.000
O(n log n)
60.000 ms
~ 5.000
O(n^2)
O(n^3)
O(2^n)
O(n!)
60.000 ms
60.000 ms
60.000 ms
60.000 ms
244
39
16
8
Comment
Best
A very very large number
Still a very big number
Moderate, average real life
size
small
very small
avoid if you can
extremely too small.
It may be useful to memorize the following ordering for quickly determine which
algorithm perform better asymptotically: constant < log n < n < n log n < n^2 < n^3 <
2^n < n!
Some rules of thumb
1. Biggest built in data structure "long long" is 2^63-1: 9*10^18 (up to 18 digits)
2. If you have k nested loops running about n iterations each, the program has O(n*k)
complexity
3. If your program is recursive with b recursive calls per level and has l levels, the
program O(b*l) complexity
4. Bear in mind that there are n! permutations and 2^n subsets or combinations of n
elements when dealing with those kinds of algorithms
CHAPTER 2
23
You've done it. Identifying the problem, designing the best possible algorithm, you have
calculate using time/space complexity, that it will be within time and memory limit given.,
and you have code it so well. But, is it 100% correct?
Depends on the programming contest's type, you may or may not get credit by solving the
problem partially. In ACM ICPC, you will only get credit if your team's code solve all the
test cases, that's it, you'll get either Accepted or Not Accepted (Wrong Answer, Time
Limit Exceeded, etc). In IOI, there exist partial credit system, in which you will get score:
number of correct/total number of test cases for each code that you submit.
In either case, you will need to be able to design a good, educated, tricky test cases.
Sample input-output given in problem description is by default too trivial and therefore
not a good way to measure your code's correctness for all input instances.
Rather than wasting your submission (and gaining time or points penalty) by getting
wrong answer, you may want to design some tricky test cases first, test it in your own
machine, and ensure your code is able to solve it correctly (otherwise, there is no point
submitting your solution right?).
Some team coaches sometime ask their students to compete with each other by designing
test cases. If student A's test cases can break other student's code, then A will get bonus
point. You may want to try this in your school team training too.
Here is some guidelines in designing good test cases:
1. Must include sample input, the most trivial one, you even have the answer given.
2. Must include boundary cases, what is the maximum n,x,y, or other input variables, try
varying their values to test for out of bound errors.
3. For multiple input test case, try using two identical test case consecutively. Both must
output the same result. This is to check whether you forgot to initialize some variables,
which will be easily identified if the first instance produce correct output but the second
one doesn't.
4. Increase the size of input. Sometimes your program works for small input size, but
behave wrongly when input size increases.
5. Tricky test cases, analyze the problem description and identify parts that are tricky, test
them to your code.
6. Don't assume input will always nicely formatted if the problem description didn't say
CHAPTER 2
24
so. Try inserting white spaces (space, tabs) in your input, check whether your code is able
to read in the values correctly
7. Finally, do random test cases, try random input and check your code's correctness.
Producing Winning Solution
A good way to get a competitive edge is to write down a game plan for what you're going
to do in a contest round. This will help you script out your actions, in terms of what to do
both when things go right and when things go wrong. This way you can spend your
thinking time in the round figuring out programming problems and not trying to figure out
what the heck you should do next... it's sort of like Pre-Computing your reactions to most
situations.
Read through all the problems first, don't directly attempt one problem since you may
missed easier problem.
1. Order the problems: shortest job first, in terms of your effort (shortest to longest:
done it before, easy, unfamiliar, hard).
2. Sketch the algorithms, complexity, the numbers, data structures, tricky details.
3. Brainstorm other possible algorithms (if any) - then pick the stupidest that works!
4. Do the Math! (space & time complexity & plug-in actual expected & worst case
numbers).
5. Code it of course, as fast as possible, and it must be correct.
6. Try to break the algorithm - use special (degenerate?) test cases.
Coding a problem
Have a plan for what to do when various (foreseeable!) things go wrong; imagine
problems you might have and figure out how you want to react. The central question is:
CHAPTER 2
25
"When do you spend more time debugging a program, and when do you cut your losses
and move on?". Consider these issues:
1. How long have you spent debugging it already?
2. What type of bug do you seem to have?
3. Is your algorithm wrong?
4. Do you data structures need to be changed?
5. Do you have any clue about what's going wrong?
6. A short amount (20 mins) of debugging is better than switching to anything else;
but you might be able to solve another from scratch in 45 mins.
7. When do you go back to a problem you've abandoned previously?
8. When do you spend more time optimizing a program, and when do you switch?
9. Consider from here out - forget prior effort, focus on the future: how can you get
the most points in the next hour with what you have?
Tips & tricks for contests
1. Brute force when you can, Brute force algorithm tends to be the easiest to
implement.
2. KISS: Simple is smart! (Keep It Simple, Stupid !!! / Keep It Short & Simple).
3. Hint: focus on limits (specified in problem statement).
4. Waste memory when it makes your life easier (trade memory space for speed).
5. Don't delete your extra debugging output, comment it out.
6. Optimize progressively, and only as much as needed.
7. Keep all working versions!
8. Code to debug:
a. white space is good,
b. use meaningful variable names,
c. don't reuse variables, (we are not doing software engineering here)
d. stepwise refinement,
e. Comment before code.
9. Avoid pointers if you can.
10. Avoid dynamic memory like the plague: statically allocate everything. (yeah
yeah)
11. Try not to use floating point; if you have to, put tolerances in everywhere (never
test equality)
12. Comments on comments:
a. Not long prose, just brief notes.
b. Explain high-level functionality: ++i; /* increase the value of i by */ is
worse than useless.
c. Explain code trickery.
d. Delimit & document functional sections.
CHAPTER 2
26
Keep a log of your performance in each contest: successes, mistakes, and what you could
have done better; use this to rewrite and improve your game plan!
The Judges Are Evil and Out to Get You
Judges don't want to put easy problems on the contest, because they have thought up too
many difficult problems. So what we do is hide the easy problems, hoping that you will
be tricked into working on the harder ones. If we want you to add two non-negative
numbers together, there will be pages of text on the addition of `0' to the number system
and 3D-pictures to explain the process of addition as it was imagined on some island that
nobody has ever heard of.
Once we've scared you away from the easy problems, we make the hard ones look easy.
`Given two polygons, find the area of their intersection.' Easy, right?
It isn't always obvious that a problem is easy, so teams ignore the problems or start on
overly complex approaches to them. Remember, there are dozens of other teams working
on the same problems, and they will help you find the easy problems. If everyone is
solving problem G, maybe you should take another look at it.[6]
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
27
A C program consists of one or more functions, which are similar to the functions and
subroutines of a Fortran program or the procedures of PL/I, and perhaps some external data
definitions. main is such a function, and in fact all C programs must have a main.
Execution of the program begins at the first statement of main. main will usually invoke
other functions to perform its job, some coming from the same program, and others from
libraries.
main( ) {
printf("hello, world");
}
printf is a library function which will format and print output on the terminal (unless
some other destination is specified). In this case it prints
hello, world
Here's a bigger program that adds three integers and prints their sum.
main( ) {
int a, b, c, sum;
a = 1; b = 2; c = 3;
sum = a + b + c;
printf("sum is %d", sum);
}
Arithmetic and the assignment statements are much the same as in Fortran (except for the
semicolons) or PL/I. The format of C programs is quite free. We can put several
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
28
statements on a line if we want, or we can split a statement among several lines if it seems
desirable. The split may be between any of the operators or variables, but not in the
middle of a name or operator. As a matter of style, spaces, tabs, and newlines should be
used freely to enhance readability.
C has fundamental types of variables:
Variable Type
Keyword
Character
char
-128 to 127
Integer
int
-32768 to 32767
Short integer
short
-32768 to 32767
Long integer
long
Unsigned character
unsigned char 1
Unsigned integer
unsigned int
-2,147,483,648 to 2,147,438,647
0 to 255
0 to 65535
0 to 65535
0 to 4,294,967,295
Single-precision
1.2E-38 to
float
floating-point
Double-precision
3.4E38
double
floating-point
2.2E-308 to
1.8E3082
There are also arrays and structures of these basic types, pointers to them and functions that
return them, all of which we will meet shortly.
All variables in a C program must be declared, although this can sometimes be done
implicitly by context. Declarations must precede executable statements. The declaration
int a, b, c, sum;
Variable names have one to eight characters, chosen from A-Z, a-z, 0-9, and _, and start
with a non-digit.
Constants
We have already seen decimal integer constants in the previous example-- 1, 2, and 3.
Since C is often used for system programming and bit-manipulation, octal numbers are an
important part of the language. In C, any number that begins with 0 (zero!) is an octal
integer (and hence can't have any 8's or 9's in it). Thus 0777 is an octal constant, with
decimal value 511.
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
29
A ``character'' is one byte (an inherently machine-dependent concept). Most often this is
expressed as a character constant, which is one character enclosed in single quotes.
However, it may be any quantity that fits in a byte, as in flags below:
char quest, newline, flags;
quest = '?';
newline = '\n';
flags = 077;
The sequence `\n' is C notation for ``newline character'', which, when printed, skips the
terminal to the beginning of the next line. Notice that `\n' represents only a single
character. There are several other ``escapes'' like `\n' for representing hard-to-get or
invisible characters, such as `\t' for tab, `\b' for backspace, `\0' for end of file, and `\\' for the
backslash itself.
Simple I/O getchar(), putchar(), printf ()
getchar and putchar are the basic I/O library functions in C. getchar fetches one
character from the standard input (usually the terminal) each time it is called, and returns
that character as the value of the function. When it reaches the end of whatever file it is
reading, thereafter it returns the character represented by `\0' (ascii NUL, which has value
zero). We will see how to use this very shortly.
main( ) {
char c;
c = getchar( );
putchar(c);
}
putchar puts one character out on the standard output (usually the terminal) each time it is
called. So the program above reads one character and writes it back out. By itself, this isn't
very interesting, but observe that if we put a loop around this, and add a test for end of file,
we have a complete program for copying one file to another.
printf is a more complicated function for producing formatted output.
printf ("hello, world\n");
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
30
prints
sum is 6
Within the first argument of printf, the characters ``%d'' signify that the next argument in
the argument list is to be printed as a base 10 number.
Other useful formatting commands are ``%c'' to print out a single character, ``%s'' to print
out an entire string, and ``%o'' to print a number as octal instead of decimal (no leading
zero). For example,
n = 511;
printf ("What is the value of %d in octal?", n);
printf ("%s! %d decimal is %o octal\n", "Right", n, n);
prints
What is the value of 511 in octal?
is 777 octal
Right! 511
decimal
CHAPTER 3
<
>=
<=
PROGRAMMING IN C: A TUTORIAL
31
less than
greater than or equal to
less than or equal to
The value of ``expression relation expression'' is 1 if the relation is true, and 0 if false.
Don't forget that the equality test is `=='; a single `=' causes an assignment, not a test, and
invariably leads to disaster.
Tests can be combined with the operators `&&' (AND), `||' (OR), and `!' (NOT). For
example, we can test whether a character is blank or tab or newline with
if( c==' ' || c=='\t' || c=='\n' ) ...
C guarantees that `&&' and `||' are evaluated left to right -- we shall soon see cases where
this matters.
As a simple example, suppose we want to ensure that a is bigger than b, as part of a sort
routine. The interchange of a and b takes three statements in C, grouped together by {}:
if (a < b) {
t = a;
a = b;
b = t;
}
As a general rule in C, anywhere you can use a simple statement, you can use any
compound statement, which is just a number of simple or compound ones enclosed in {}.
There is no semicolon after the } of a compound statement, but there is a semicolon after
the last non-compound statement inside the {}.
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
32
Its meaning is
(a) evaluate the expression
(b) if its value is true (i.e., not zero) do the statement, and go back to (a)
Because the expression is tested before the statement is executed, the statement part can be
executed zero times, which is often desirable. As in the if statement, the expression and the
statement can both be arbitrarily complicated, although we haven't seen that yet. Our
example gets the character, assigns it to c, and then tests if it's a `\0''. If it is not a `\0', the
statement part of the while is executed, printing the character. The while then repeats.
When the input character is finally a `\0', the while terminates, and so does main.
Notice that we used an assignment statement
c = getchar( )
within an expression. This is a handy notational shortcut which often produces clearer
code. (In fact it is often the only way to write the code cleanly. As an exercise, rewrite the
file-copy without using an assignment inside an expression.) It works because an
assignment statement has a value, just as any other expression does. Its value is the value of
the right hand side. This also implies that we can use multiple assignments like
x = y = z = 0;
c would be set to 0 or 1 depending on whether the character fetched was an end of file or
not. This is because in the absence of parentheses the assignment operator `=' is evaluated
after the relational operator `!='. When in doubt, or even if not, parenthesize.
main( ) {
while( putchar(getchar( )) != '\0' ) ;
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
33
What statement is being repeated? None, or technically, the null statement, because all the
work is really done within the test part of the while. This version is slightly different from
the previous one, because the final `\0' is copied to the output before we decide to stop.
Arithmetic
The arithmetic operators are the usual `+', `-', `*', and `/' (truncating integer division if the
operands are both int), and the remainder or mod operator `%':
x = a%b;
sets x to the remainder after a is divided by b (i.e., a mod b). The results are machine
dependent unless a and b are both positive.
In arithmetic, char variables can usually be treated like int variables. Arithmetic on
characters is quite legal, and often makes sense:
c = c + 'A' - 'a';
converts a single lower case ascii character stored in c to upper case, making use of the fact
that corresponding ascii letters are a fixed distance apart. The rule governing this
arithmetic is that all chars are converted to int before the arithmetic is done. Beware that
conversion may involve sign-extension if the leftmost bit of a character is 1, the resulting
integer might be negative. (This doesn't happen with genuine characters on any current
machine.)
So to convert a file into lower case:
main( ) {
char c;
while( (c=getchar( )) != '\0' )
if( 'A'<=c && c<='Z' )
putchar(c+'a'-'A');
else
putchar(c); }
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
34
the else part is optional, but often useful. The canonical example sets x to the minimum
of a and b:
if (a < b)
x = a;
else
x = b;
C provides an alternate form of conditional which is often more concise. It is called the
``conditional expression'' because it is a conditional which actually has a value and can be
used anywhere an expression can. The value of
a<b ? a : b;
The parentheses aren't necessary because `?:' is evaluated before `=', but safety first.
Going a step further, we could write the loop in the lower-case program as
while( (c=getchar( )) != '\0' )
putchar( ('A'<=c && c<='Z') ? c-'A'+'a' : c );
If's and else's can be used to construct logic that branches one of several ways and then
rejoins, a common programming structure, in this way:
if(...)
{...}
else if(...)
{...}
else if(...)
{...}
else
{...}
The conditions are tested in order, and exactly one block is executed; either the first one
whose if is satisfied, or the one for the last else. When this block is finished, the next
statement executed is the one after the last else. If no action is to be taken for the
``default'' case, omit the last else.
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
35
For example, to count letters, digits and others in a file, we could write
main( ) {
int let, dig, other, c;
let = dig = other = 0;
while( (c=getchar( )) != '\0' )
if( ('A'<=c && c<='Z') || ('a'<=c && c<='z') )
++let;
else if( '0'<=c && c<='9' ) ++dig;
else ++other;
printf("%d letters, %d digits, %d others\n", let, dig, other);
}
In addition to the usual `-', C also has two other interesting unary operators, `++'
(increment) and `--' (decrement). Suppose we want to count the lines in a file.
main( ) {
int c,n;
n = 0;
while( (c=getchar( )) != '\0' )
if( c == '\n' )
++n;
printf("%d lines\n", n);
}
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
36
first sets x to to 5, and then increments k to 6. The incrementing effect of ++k and k++ is
the same, but their values are respectively 5 and 6. We shall soon see examples where both
of these uses are important.
Arrays
In C, as in Fortran or PL/I, it is possible to make arrays whose elements are basic types.
Thus we can make an array of 10 integers with the declaration
int x[10];
The square brackets mean subscripting; parentheses are used only for function references.
Array indexes begin at zero, so the elements of x are
x[0], x[1], x[2], ..., x[9]
Subscripts can be arbitrary integer expressions. Multi-dimension arrays are stored by row
(opposite to Fortran), so the rightmost subscript varies fastest; name has 10 rows and 20
columns.
Here is a program which reads a line, stores it in a buffer, and prints its length (excluding
the newline at the end).
main( ) {
int n, c;
char line[100];
n = 0;
while( (c=getchar( )) != '\n' ) {
if( n < 100 )
line[n] = c;
n++;
}
printf("length = %d\n", n);
}
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
37
As a more complicated problem, suppose we want to print the count for each line in the
input, still storing the first 100 characters of each line. Try it as an exercise before looking
at the solution:
main( ) {
int n, c; char line[100];
n = 0;
while( (c=getchar( )) != '\0' )
if( c == '\n' ) {
printf("%d, n);
n = 0;
}
else {
if( n < 100 ) line[n] = c;
n++;
}
}
Text is usually kept as an array of characters, as we did with line[ ] in the example above.
By convention in C, the last character in a character array should be a `\0' because most
programs that manipulate character arrays expect it. For example, printf uses the `\0' to
detect the end of a character array when printing it out with a `%s'.
We can copy a character array s into another t like this:
i = 0;
while( (t[i]=s[i]) != '\0' )
i++;
Most of the time we have to put in our own `\0' at the end of a string; if we want to print the
line with printf, it's necessary. This code prints the character count before the line:
main( ) {
int n;
char line[100];
n = 0;
while( (line[n++]=getchar( )) != '\n' );
line[n] = '\0';
printf("%d:\t%s", n, line);
}
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
38
Here we increment n in the subscript itself, but only after the previous value has been used.
The character is read, placed in line[n], and only then n is incremented.
There is one place and one place only where C puts in the `\0' at the end of a character array
for you, and that is in the construction
"stuff between double quotes"
The compiler puts a `\0' at the end automatically. Text enclosed in double quotes is called a
string; its properties are precisely those of an (initialized) array of characters.
for Statement
The for statement is a somewhat generalized while that lets us put the initialization and
increment parts of a loop into a single statement along with the test. The general form of
the for is
for( initialization; expression; increment )
statement
In the for statement, the initialization can be left out if you want, but the semicolon has to
be there. The increment is also optional. It is not followed by a semicolon. The second
clause, the test, works the same way as in the while: if the expression is true (not zero) do
another loop, otherwise get on with the next statement. As with the while, the for loop
may be done zero times. If the expression is left out, it is taken to be always true, so
for( ; ; ) ...
while( 1 ) ...
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
39
You might ask why we use a for since it's so much like a while. (You might also ask why
we use a while because...) The for is usually preferable because it keeps the code where
it's used and sometimes eliminates the need for compound statements, as in this code that
zeros a two-dimensional array:
for( i=0; i<n; i++ )
for( j=0; j<m; j++ )
array[i][j] = 0;
Functions; Comments
Suppose we want, as part of a larger program, to count the occurrences of the ascii
characters in some input text. Let us also map illegal characters (those with value>127 or
<0) into one pile. Since this is presumably an isolated part of the program, good practice
dictates making it a separate function. Here is one way:
main( ) {
int hist[129];
...
count(hist, 128);
printf( ... );
...
/* anywhere blanks,
}
/*
count(buf, size)
int size, buf[ ]; {
int i, c;
for( i=0; i<=size; i++ )
buf[i] = 0;
/* set buf to zero */
while( (c=getchar( )) != '\0' ) {
/* read til eof */
if( c > size || c < 0 )
c = size;
/* fix illegal input */
buf[c]++;
}
return;
}
We have already seen many examples of calling a function, so let us concentrate on how to
define one. Since count has two arguments, we need to declare them, as shown, giving
their types, and in the case of buf, the fact that it is an array. The declarations of arguments
go between the argument list and the opening `{'. There is no need to specify the size of the
array buf, for it is defined outside of count.
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
40
The return statement simply says to go back to the calling routine. In fact, we could have
omitted it, since a return is implied at the end of a function.
What if we wanted count to return a value, say the number of characters read? The return
statement allows for this too:
int i, c, nchar;
nchar = 0;
...
while( (c=getchar( )) != '\0' ) {
if( c > size || c < 0 )
c = size;
buf[c]++;
nchar++;
}
return(nchar);
Any expression can appear within the parentheses. Here is a function to compute the
minimum of two integers:
min(a, b)
int a, b; {
return( a < b ? a : b );
}
As is often the case, all the work is done by the assignment statement embedded in the test
part of the for. Again, the declarations of the arguments s1 and s2 omit the sizes, because
they don't matter to strcopy. (In the section on pointers, we will see a more efficient way to
do a string copy.)
There is a subtlety in function usage which can trap the unsuspecting Fortran programmer.
Simple variables (not arrays) are passed in C by ``call by value'', which means that the
called function is given a copy of its arguments, and doesn't know their addresses. This
makes it impossible to change the value of one of the actual input arguments.
There are two ways out of this dilemma. One is to make special arrangements to pass to
the function the address of a variable instead of its value. The other is to make the variable
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
41
a global or external variable, which is known to each function by its name. We will discuss
both possibilities in the next few sections.
Local and External Variables
If we say
f( ) {
}
g( ) {
int x;
...
int x;
...
each x is local to its own routine -- the x in f is unrelated to the x in g. (Local variables are
also called ``automatic''.) Furthermore each local variable in a routine appears only when
the function is called, and disappears when the function is exited. Local variables have no
memory from one call to the next and must be explicitly initialized upon each entry. (There
is a static storage class for making local variables with memory; we won't discuss it.)
As opposed to local variables, external variables are defined external to all functions, and
are (potentially) available to all functions. External storage always remains in existence.
To make variables external we have to define them external to all functions, and, wherever
we want to use them, make a declaration.
main( ) {
extern
...
count(
...
}
count( ) {
extern
int i,
...
}
int
int
hist[129];
nchar;
Roughly speaking, any function that wishes to access an external variable must contain an
extern declaration for it. The declaration is the same as others, except for the added
keyword extern. Furthermore, there must somewhere be a definition of the external
variables external to all functions.
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
42
External variables can be initialized; they are set to zero if not explicitly initialized. In its
simplest form, initialization is done by putting the value (which must be a constant) after
the definition:
Pointers
A pointer in C is the address of something. It is a rare case indeed when we care what the specific
address itself is, but pointers are a quite common way to get at the contents of something.
The unary operator `&' is used to produce the address of an object, if it has one. Thus
int a, b;
b = &a;
puts the address of a into b. We can't do much with it except print it or pass it to some other
routine, because we haven't given b the right kind of declaration. But if we declare that b is indeed
a pointer to an integer, we're in good shape:
int a, *b, c;
b = &a;
c = *b;
b contains the address of a and `c = *b' means to use the value in b as an address, i.e., as a
pointer. The effect is that we get back the contents of a, albeit rather indirectly. (It's always the
case that `*&x' is the same as x if x has an address.)
The most frequent use of pointers in C is for walking efficiently along arrays. In fact, in
the implementation of an array, the array name represents the address of the zeroth element
of the array, so you can't use it on the left side of an expression. (You can't change the
address of something by assigning to it.) If we say
char *y;
y
char x[100];
is of type pointer to character (although it doesn't yet point anywhere). We can make y
gives x[1]
gives x[i]
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
43
You can now see why we have to say what kind of thing s points to -- if we're to increment it
with s++ we have to increment it by the right amount.
The pointer version is more efficient (this is almost always true) but even more compact is
for( n=0; *s++ != '\0'; n++ );
The `*s' returns a character; the `++' increments the pointer so we'll get the next character
next time around. As you can see, as we make things more efficient, we also make them less
clear. But `*s++' is an idiom so common that you have to know it.
Going a step further, here's our function strcopy that copies a character array s to another t.
strcopy(s,t)
char *s, *t; {
while(*t++ = *s++);
}
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
44
We have omitted the test against `\0', because `\0' is identically zero; you will often see the
code this way.
For arguments to a function, and there only, the declarations
char s[ ];
char *s;
are equivalent -- a pointer to a type, or an array of unspecified size of that type, are the
same thing.
Function Arguments
Look back at the function strcopy in the previous section. We passed it two string names as
arguments, then proceeded to clobber both of them by incrementation. So how come we don't lose
the original strings in the function that called strcopy?
As we said before, C is a ``call by value'' language: when you make a function call like f(x),
the value of x is passed, not its address. So there's no way to alter x from inside f. If x is
an array (char x[10]) this isn't a problem, because x is an address anyway, and you're not
trying to change it, just what it addresses. This is why strcopy works as it does. And it's
convenient not to have to worry about making temporary copies of the input arguments.
But what if x is a scalar and you do want to change it? In that case, you have to pass the
address of x to f, and then use it as a pointer. Thus for example, to interchange two
integers, we must write
flip(x, y)
int *x, *y; {
int temp;
temp = *x;
*x = *y;
*y = temp;
}
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
45
testing a value against a series of constants, the switch statement is often clearer and
usually gives better code. Use it like this:
switch( c ) {
case 'a':
aflag++;
break;
case 'b':
bflag++;
break;
case 'c':
cflag++;
break;
default:
printf("%c?\n", c);
break;
}
The case statements label the various actions we want; default gets done if none of the
other cases are satisfied. (A default is optional; if it isn't there, and none of the cases
match, you just fall out the bottom.)
The break statement in this example is new. It is there because the cases are just labels,
and after you do one of them, you fall through to the next unless you take some explicit
action to escape. This is a mixed blessing. On the positive side, you can have multiple
cases on a single statement; we might want to allow both upper and lower
But what if we just want to get out after doing case `a' ? We could get out of a case of the
switch with a label and a goto, but this is really ugly. The break statement lets us exit without
either goto or label.
The break statement also works in for and while statements; it causes an immediate exit
from the loop.
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
46
The continue statement works only inside for's and while's; it causes the next iteration of
the loop to be started. This means it goes to the increment part of the for and the test part
of the while.
Structures
The main use of structures is to lump together collections of disparate variable types, so
they can conveniently be treated as a unit. For example, if we were writing a compiler or
assembler, we might need for each identifier information like its name (a character array), its source
line number (an integer), some type information (a character, perhaps), and probably a usage count
(another integer).
char
int
char
int
id[10];
line;
type;
usage;
We can make a structure out of this quite easily. We first tell C what the structure will
look like, that is, what kinds of things it contains; after that we can actually reserve storage
for it, either in the same statement or separately. The simplest thing is to define it and
allocate storage all at once:
struct {
char
int
char
int
id[10];
line;
type;
usage;
} sym;
This defines sym to be a structure with the specified shape; id, line, type and usage are
members of the structure. The way we refer to any particular member of the structure is
structure-name . member
as in
sym.type = 077;
if( sym.usage == 0 ) ...
while( sym.id[j++] ) ...
etc.
Although the names of structure members never stand alone, they still have to be unique;
there can't be another id or usage in some other structure.
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
47
So far we haven't gained much. The advantages of structures start to come when we have
arrays of structures, or when we want to pass complicated data layouts between functions.
Suppose we wanted to make a symbol table for up to 100 identifiers. We could extend our
definitions like
char
int
char
int
id[100][10];
line[100];
type[100];
usage[100];
but a structure lets us rearrange this spread-out information so all the data about a single
identifer is collected into one lump:
struct {
char
int
char
int
} sym[100];
id[10];
line;
type;
usage;
This makes sym an array of structures; each array element has the specified shape. Now we
can refer to members as
sym[i].usage++; /* increment usage of i-th identifier */
for( j=0; sym[i].id[j++] != '\0'; ) ...
etc.
Thus to print a list of all identifiers that haven't been used, together with their line number,
for( i=0; i<nsym; i++ )
if( sym[i].usage == 0 )
printf("%d\t%s\n", sym[i].line, sym[i].id);
Suppose we now want to write a function lookup(name) which will tell us if name already
exists in sym, by giving its index, or that it doesn't, by returning a -1. We can't pass a
structure to a function directly; we have to either define it externally, or pass a pointer to it.
Let's try the first way first.
int
nsym
struct {
char
int
char
int
} sym[100];
0;
id[10];
line;
type;
usage;
/* symbol table */
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
48
main( ) {
...
if( (index = lookup(newname)) >= 0 )
sym[index].usage++;
/* already there ... */
else
install(newname, newline, newtype);
...
}
lookup(s)
char *s; {
int i;
extern struct {
char
id[10];
int
line;
char
type;
int
usage;
} sym[ ];
for( i=0; i<nsym; i++ )
if( compar(s, sym[i].id) > 0 )
return(i);
return(-1);
}
compar(s1,s2)
/* return 1 if s1==s2, 0 otherwise */
char *s1, *s2; {
while( *s1++ == *s2 )
if( *s2++ == '\0' )
return(1);
return(0);
}
The declaration of the structure in lookup isn't needed if the external definition precedes its
use in the same source file, as we shall see in a moment.
Now what if we want to use pointers?
struct
symtag {
char
id[10];
int
line;
char
type;
int
usage;
} sym[100], *psym;
psym = &sym[0]; /* or p = sym; */
This makes psym a pointer to our kind of structure (the symbol table), then initializes it to point to
the first element of sym.
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
49
Notice that we added something after the word struct: a ``tag'' called symtag. This puts a
name on our structure definition so we can refer to it later without repeating the definition.
It's not necessary but useful. In fact we could have said
struct
symtag {
... structure definition
};
which wouldn't have assigned any storage at all, and then said
struct
struct
symtag
symtag
sym[100];
*psym;
which would define the array and the pointer. This could be condensed further, to
struct
symtag
sym[100], *psym;
The symbol `->' means we're pointing at a member of a structure; `->' is only used in that
context. ptr is a pointer to the (base of) a structure that contains the structure member. The
expression ptr->structure-member refers to the indicated member of the pointed-to structure. Thus
we have constructions like:
psym->type = 1;
psym->id[0] = 'a';
For more complicated pointer expressions, it's wise to use parentheses to make it clear who
goes with what. For example,
struct { int x, *y; } *p;
p->x++ increments x
++p->x so does this!
(++p)->x
increments p before getting x
*p->y++ uses y as a pointer, then increments it
*(p->y)++
so does this
*(p++)->y
uses y as a pointer, then increments p
The way to remember these is that ->, . (dot), ( ) and [ ] bind very tightly. An expression
involving one of these is treated as a unit. p->x, a[i], y.x and f(b) are names exactly as abc is.
If p is a pointer to a structure, any arithmetic on p takes into account the actual size of the
structure. For instance, p++ increments p by the correct amount to get the next element of
the array of structures. But don't assume that the size of a structure is the sum of the sizes
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
50
of its members -- because of alignments of different sized objects, there may be ``holes'' in
a structure.
Enough theory. Here is the lookup example, this time with pointers.
struct symtag {
char
id[10];
int
line;
char
type;
int
usage;
} sym[100];
main( ) {
struct symtag *lookup( );
struct symtag *psym;
...
if( (psym = lookup(newname)) ) /* non-zero pointer */
psym -> usage++;
/* means already there */
else
install(newname, newline, newtype);
...
}
struct symtag *lookup(s)
char *s; {
struct symtag *p;
for( p=sym; p < &sym[nsym]; p++ )
if( compar(s, p->id) > 0)
return(p);
return(0);
}
This brings us to an area that we will treat only hurriedly; the question of function types.
So far, all of our functions have returned integers (or characters, which are much the same). What
do we do when the function returns something else, like a pointer to a structure? The rule is that
any function that doesn't return an int has to say explicitly what it does return. The type
information goes before the function name (which can make the name hard to see).
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
51
Examples:
char f(a)
int a; {
...
}
int *g( ) { ... }
struct symtag *lookup(s) char *s; { ... }
The function f returns a character, g returns a pointer to an integer, and lookup returns a pointer to
a structure that looks like symtag. And if we're going to use one of these functions, we have to
make a declaration where we use it, as we did in main above.
In effect, this says that lookup( ) and psym are both used the same way - as a pointer to a
structure -- even though one is a variable and the other is a function.
Initialization of Variables
An external variable may be initialized at compile time by following its name with an
initializing value when it is defined. The initializing value has to be something whose value is
known at compile time, like a constant.
int
int
x =
*p
0;
&y[1];
An external array can be initialized by following its name with a list of initializations
enclosed in braces:
int
x[4] =
{0,1,2,3}; /* makes x[i] = i */
int
y[ ] = {0,1,2,3}; /* makes y big enough for 4 values */
char
*msg = "syntax error\n";
/* braces unnecessary here */
char *keyword[ ]={
"if",
"else",
"for",
"while",
"break",
"continue",
0
};
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
52
This last one is very useful -- it makes keyword an array of pointers to character strings,
with a zero at the end so we can identify the last element easily. A simple lookup routine
could scan this until it either finds a match or encounters a zero keyword pointer:
lookup(str)
/* search for str in keyword[ ] */
char *str; {
int i,j,r;
for( i=0; keyword[i] != 0; i++) {
for( j=0; (r=keyword[i][j]) == str[j] && r != '\0'; j++
);
if( r == str[j] )
return(i);
}
return(-1);
}
Scope Rules
A complete C program need not be compiled all at once; the source text of the program
may be kept in several files, and previously compiled routines may be loaded from
libraries. How do we arrange that data gets passed from one routine to another? We have already
seen how to use function arguments and values, so let us talk about external data. Warning: the
words declaration and definition are used precisely in this section; don't treat them as the same thing.
A major shortcut exists for making extern declarations. If the definition of a variable
appears before its use in some function, no extern declaration is needed within the
function. Thus, if a file contains
f1(
int
f2(
f3(
) { ... }
foo;
) { ... foo = 1; ... }
) { ... if ( foo ) ... }
no declaration of foo is needed in either f2 or or f3, because the external definition of foo
appears before them. But if f1 wants to use foo, it has to contain the declaration
f1( ) {
extern int foo;
...
}
This is true also of any function that exists on another file; if it wants foo it has to use an
extern declaration for it. (If somewhere there is an extern declaration for something, there must also
eventually be an external definition of it, or you'll get an ``undefined symbol'' message.)
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
53
There are some hidden pitfalls in external declarations and definitions if you use multiple
source files. To avoid them, first, define and initialize each external variable only once in
the entire set of files:
int
foo
0;
You can get away with multiple external definitions on UNIX, but not on GCOS, so don't
ask for trouble. Multiple initializations are illegal everywhere. Second, at the beginning of any
file that contains functions needing a variable whose definition is in some other file, put in an extern
declaration, outside of any function:
extern
int
foo;
f1( ) { ... }
etc.
#define, #include
something
and thereafter anywhere ``name'' appears as a token, ``something'' will be substituted. This
is particularly useful in parametering the sizes of arrays:
#define ARRAYSIZE
100
int
arr[ARRAYSIZE];
...
while( i++ < ARRAYSIZE )...
(now we can alter the entire program by changing only the define) or in setting up
mysterious constants:
#define
#define
#define
...
if( x &
SET
INTERRUPT
ENABLED 04
01
02
/* interrupt bit */
Now we have meaningful words instead of mysterious constants. (The mysterious operators
`&' (AND) and `|' (OR) will be covered in the next section.) It's an excellent practice to write
programs without any literal constants except in #define statements.
There are several warnings about #define. First, there's no semicolon at the end of a
#define; all the text from the name to the end of the line (except for comments) is taken to
be the ``something''. When it's put into the text, blanks are placed around it. The other
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
54
control word known to C is #include. To include one file in your source at compilation
time, say
#include "filename"
Bit Operators
C has several operators for logical bit-operations. For example,
x = x & 0177;
forms the bit-wise AND of x and 0177, effectively retaining only the last seven bits of x. Other
operators are
|
^
~
!
<<
>>
IBM360)
inclusive OR
(circumflex) exclusive OR
(tilde) 1's complement
logical NOT
left shift (as in x<<2)
right shift
(arithmetic on PDP-11;
logical on H6070,
Assignment Operators
An unusual feature of C is that the normal binary operators like `+', `-', etc. can be
combined with the assignment operator `=' to form new assignment operators. For example,
x =- 10;
forms the AND of x and 0177. This convention is a useful notational shortcut, particularly if x is
a complicated expression. The classic example is summing an array:
for( sum=i=0; i<n; i++ )
sum =+ array[i];
also decreases x by 10. This is quite contrary to the experience of most programmers. In
particular, watch out for things like
c=*s++;
y=&x[0];
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
55
both of which are almost certainly not what you wanted. Newer versions of various compilers
are courteous enough to warn you about the ambiguity.
Because all other operators in an expression are evaluated before the assignment operator,
the order of evaluation should be watched carefully:
x = x<<y | z;
All floating arithmetic is done in double precision. Mixed mode arithmetic is legal; if an
arithmetic operator in an expression has both operands int or char, the arithmetic done is
integer, but if one operand is int or char and the other is float or double, both operands
are converted to double. Thus if i and j are int and x is float,
(x+i)/j
x + i/j
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
56
will format floating point numbers: ``%w.df'' in the format string will print the
corresponding variable in a field w digits wide, with d decimal places. An e instead of an f
printf
One use of goto's with some legitimacy is in a program which contains a long loop, where a
while(1) would be too extended. Then you might write
mainloop:
...
goto mainloop;
Another use is to implement a break out of more than one level of for or while. goto's can
only branch to labels within the same function.
Manipulating Strings
A string is a sequence of characters, with its beginning indicated by a pointer and its end
marked by the null character \0. At times, you need to know the length of a string (the
number of characters between the start and the end of the string) [5]. This length is obtained
with the library function strlen(). Its prototype, in STRING.H, is
size_t strlen(char *str);
The library function strcpy() copies an entire string to another memory location. Its
prototype is as follows:
char *strcpy( char *destination, char *source );
Before using strcpy(), you must allocate storage space for the destination string.
/* Demonstrates strcpy(). */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char source[] = "The source string.";
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
57
main()
{
char dest1[80];
char *dest2, *dest3;
printf("\nsource: %s", source );
/* Copy to dest1 is okay because dest1 points to */
/* 80 bytes of allocated space. */
strcpy(dest1, source);
printf("\ndest1: %s", dest1);
/* To copy to dest2 you must allocate space. */
dest2 = (char *)malloc(strlen(source) +1);
strcpy(dest2, source);
printf("\ndest2: %s\n", dest2);
return(0);
}
source: The source string.
dest1: The source string.
dest2: The source string.
The strncpy() function is similar to strcpy(), except that strncpy() lets you specify how
many characters to copy. Its prototype is
char *strncpy(char *destination, char *source, size_t n);
/* Using the strncpy() function. */
#include <stdio.h>
#include <string.h>
char dest[] = "..........................";
char source[] = "abcdefghijklmnopqrstuvwxyz";
main()
{
size_t n;
while (1)
{
puts("Enter the number of characters to copy (1-26)");
scanf("%d", &n);
if (n > 0 && n< 27)
break;
}
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
58
The library function strdup() is similar to strcpy(), except that strdup() performs its own
memory allocation for the destination string with a call to malloc().The prototype for
strdup() is
char *strdup( char *source );
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
59
The function appends a copy of str2 onto the end of str1, moving the terminating null
character to the end of the new string. You must allocate enough space for str1 to hold the
resulting string. The return value of strcat() is a pointer to str1. Following listing
demonstrates strcat().
/* The strcat() function. */
#include <stdio.h>
#include <string.h>
char str1[27] = "a";
char str2[2];
main()
{
int n;
/* Put a null character at the end of str2[]. */
str2[1] = `\0';
for (n = 98; n< 123; n++)
{
str2[0] = n;
strcat(str1, str2);
puts(str1);
}
return(0);
}
ab
abc
abcd
abcde
abcdef
abcdefg
abcdefgh
abcdefghi
abcdefghij
abcdefghijk
abcdefghijkl
abcdefghijklm
abcdefghijklmn
abcdefghijklmno
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
60
abcdefghijklmnop
abcdefghijklmnopq
abcdefghijklmnopqr
abcdefghijklmnopqrs
abcdefghijklmnopqrst
abcdefghijklmnopqrstu
abcdefghijklmnopqrstuv
abcdefghijklmnopqrstuvw
abcdefghijklmnopqrstuvwx
abcdefghijklmnopqrstuvwxy
abcdefghijklmnopqrstuvwxyz
Comparing Strings
Strings are compared to determine whether they are equal or unequal. If they are unequal,
one string is "greater than" or "less than" the other. Determinations of "greater" and "less"
are made with the ASCII codes of the characters. In the case of letters, this is equivalent to
alphabetical order, with the one seemingly strange exception that all uppercase letters are
"less than" the lowercase letters. This is true because the uppercase letters have ASCII
codes 65 through 90 for A through Z, while lowercase a through z are represented by 97
through 122. Thus, "ZEBRA" would be considered to be less than "apple" by these C
functions.
The ANSI C library contains functions for two types of string comparisons: comparing two
entire strings, and comparing a certain number of characters in two strings.
Comparing Two Entire Strings
The function strcmp() compares two strings character by character. Its prototype is
int strcmp(char *str1, char *str2);
The arguments str1 and str2 are pointers to the strings being compared. The function's
return values are given in Table. Following Listing demonstrates strcmp().
The values returned by strcmp().
Return Value
Meaning
<0
>0
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
61
The library function strncmp() compares a specified number of characters of one string to
another string. Its prototype is
int strncmp(char *str1, char *str2, size_t n);
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
62
The function strncmp() compares n characters of str2 to str1. The comparison proceeds
until n characters have been compared or the end of str1 has been reached. The method of
comparison and return values are the same as for strcmp(). The comparison is casesensitive.
Comparing parts of strings with strncmp().
/* The strncmp() function. */
#include <stdio.h>
#include[Sigma]>=tring.h>
char str1[] = "The first string.";
char str2[] = "The second string.";
main()
{
size_t n, x;
puts(str1);
puts(str2);
while (1)
{
puts("\n\nEnter number of characters to compare, 0 to exit.");
scanf("%d", &n);
if (n <= 0)
break;
x = strncmp(str1, str2, n);
printf("\nComparing %d characters, strncmp() returns %d.", n, x);
}
return(0);
}
The first string.
The second string.
Enter number of characters to compare, 0 to exit.
3
Comparing 3 characters, strncmp() returns .]
Enter number of characters to compare, 0 to exit.
6
Comparing 6 characters, strncmp() returns -1.
Enter number of characters to compare, 0 to exit.
0
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
63
The strchr() function finds the first occurrence of a specified character in a string. The
prototype is
char *strchr(char *str, int ch);
The function strchr() searches str from left to right until the character ch is found or the
terminating null character is found. If ch is found, a pointer to it is returned. If not, NULL
is returned.
When strchr() finds the character, it returns a pointer to that character. Knowing that str is a
pointer to the first character in the string, you can obtain the position of the found character
by subtracting str from the pointer value returned by strchr(). Following Listing illustrates
this. Remember that the first character in a string is at position 0. Like many of C's string
functions, strchr() is case-sensitive. For example, it would report that the character F isn't
found in the string raffle.
Using strchr() to search a string for a single character.
/* Searching for a single character with strchr(). */
#include <stdio.h>
#include <string.h>
main()
{
char *loc, buf[80];
int ch;
/* Input the string and the character. */
printf("Enter the string to be searched: ");
gets(buf);
printf("Enter the character to search for: ");
ch = getchar();
/* Perform the search. */
loc = strchr(buf, ch);
if ( loc == NULL )
printf("The character %c was not found.", ch);
else
printf("The character %c was found at position %d.\n",
ch, loc-buf);
return(0); }
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
64
The library function strcspn() searches one string for the first occurrence of any of the
characters in a second string. Its prototype is
size_t strcspn(char *str1, char *str2);
The function strcspn() starts searching at the first character of str1, looking for any of the
individual characters contained in str2. This is important to remember. The function doesn't
look for the string str2, but only the characters it contains. If the function finds a match, it
returns the offset from the beginning of str1, where the matching character is located. If it
finds no match, strcspn() returns the value of strlen(str1). This indicates that the first match
was the null character terminating the string
Searching for a set of characters with strcspn().
/* Searching with strcspn(). */
#include <stdio.h>
#include <string.h>
main()
{
char buf1[80], buf2[80];
size_t loc;
/* Input the strings. */
printf("Enter the string to be searched: ");
gets(buf1);
printf("Enter the string containing target characters: ");
gets(buf2);
/* Perform the search. */
loc = strcspn(buf1, buf2);
if ( loc == strlen(buf1) )
printf("No match was found.");
else
printf("The first match was found at position %d.\n", loc);
return(0);
}
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
65
The library function strpbrk() is similar to strcspn(), searching one string for the first
occurrence of any character contained in another string. It differs in that it doesn't include
the terminating null characters in the search. The function prototype is
char *strpbrk(char *str1, char *str2);
The function strpbrk() returns a pointer to the first character in str1 that matches any of the
characters in str2. If it doesn't find a match, the function returns NULL. As previously
explained for the function strchr(), you can obtain the offset of the first match in str1 by
subtracting the pointer str1 from the pointer returned by strpbrk() (if it isn't NULL, of
course).
The strstr() Function
The final, and perhaps most useful, C string-searching function is strstr(). This function
searches for the first occurrence of one string within another, and it searches for the entire
string, not for individual characters within the string. Its prototype is
char *strstr(char *str1, char *str2);
The function strstr() returns a pointer to the first occurrence of str2 within str1. If it finds no
match, the function returns NULL. If the length of str2 is 0, the function returns str1. When
strstr() finds a match, you can obtain the offset of str2 within str1 by pointer subtraction, as
explained earlier for strchr(). The matching procedure that strstr() uses is case-sensitive.
Using strstr() to search for one string within another.
/* Searching with strstr(). */
#include <stdio.h>
#include <string.h>
main()
{
char *loc, buf1[80], buf2[80];
/* Input the strings. */
printf("Enter the string to be searched: ");
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
66
gets(buf1);
printf("Enter the target string: ");
gets(buf2);
/* Perform the search. */
loc = strstr(buf1, buf2);
if ( loc == NULL )
printf("No match was found.\n");
else
printf("%s was found at position %d.\n", buf2, loc-buf1);
return(0);}
Enter the string to be searched: How now brown cow?
Enter the target string: cow
Cow was found at position 14.
The function strrev() reverses the order of all the characters in a string (Not ANSI
Standard). Its prototype is
char *strrev(char *str);
The order of all characters in str is reversed, with the terminating null character remaining
at the end.
String-to-Number Conversions
Sometimes you will need to convert the string representation of a number to an actual
numeric variable. For example, the string "123" can be converted to a type int variable with
the value 123. Three functions can be used to convert a string to a number. They are
explained in the following sections; their prototypes are in STDLIB.H.
The atoi() Function
The function atoi() converts the string pointed to by ptr to an integer. Besides digits, the
string can contain leading white space and a + or -- sign. Conversion starts at the beginning
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
67
of the string and proceeds until an unconvertible character (for example, a letter or
punctuation mark) is encountered. The resulting integer is returned to the calling program.
If it finds no convertible characters, atoi() returns 0. Table lists some examples.
String-to-number conversions with atoi().
String
"157"
157
"-1.6"
-1
"+50x"
50
"twelve"
"x506"
The library function atol() works exactly like atoi(), except that it returns a type long. The
function prototype is
long atol(char *ptr);
The argument str points to the string to be converted. This string can contain leading white
space and a + or -- character. The number can contain the digits 0 through 9, the decimal
point, and the exponent indicator E or e. If there are no convertible characters, atof() returns
0. Table 17.3 lists some examples of using atof().
String-to-number conversions with atof().
String
"12"
12.000000
"-0.123"
-0.123000
"123E+3"
123000.000000
"123.1e-5"
0.001231
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
68
The header file CTYPE.H contains the prototypes for a number of functions that test
characters, returning TRUE or FALSE depending on whether the character meets a certain
condition. For example, is it a letter or is it a numeral? The isxxxx() functions are actually
macros, defined in CTYPE.H.
The isxxxx() macros all have the same prototype:
int isxxxx(int ch);
In the preceding line, ch is the character being tested. The return value is TRUE (nonzero)
if the condition is met or FALSE (zero) if it isn't. Table lists the complete set of isxxxx()
macros.
The isxxxx() macros.
Macro
Action
isalnum()
isalpha()
isascii()
iscntrl()
isdigit()
isgraph()
islower()
isprint()
ispunct()
isspace()
Returns TRUE if ch is a whitespace character (space, tab, vertical tab, line feed, form feed, or carriage
return).
isupper()
isxdigit()
You can do many interesting things with the character-test macros. One example is the
function get_int(), shown in Listing. This function inputs an integer from stdin and returns
it as a type int variable. The function skips over leading white space and returns 0 if the
first nonspace character isn't a numeric character.
Using the isxxxx() macros to implement a function that inputs an integer.
/* Using character test macros to create an integer */
/* input function. */
#include <stdio.h>
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
#include <ctype.h>
int get_int(void);
main()
{
int x;
x = get_int();
printf("You entered %d.\n", x);
}
int get_int(void)
{
int ch, i, sign = 1;
while ( isspace(ch = getchar()) );
if (ch != `-' && ch != `+' && !isdigit(ch) && ch != EOF)
{
ungetc(ch, stdin);
return 0;
}
/* If the first character is a minus sign, set */
/* sign accordingly. */
if (ch == `-')
sign = -1;
/* If the first character was a plus or minus sign, */
/* get the next character. */
if (ch == `+' || ch == `-')
ch = getchar();
/* Read characters until a nondigit is input. Assign */
/* values, multiplied by proper power of 10, to i. */
for (i = 0; isdigit(ch); ch = getchar() )
i = 10 * i + (ch - `0');
/* Make result negative if sign is negative. */
i *= sign;
/* If EOF was not encountered, a nondigit character */
/* must have been read in, so unget it. */
if (ch != EOF)
ungetc(ch, stdin);
/* Return the input value. */
return i;
}
69
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
-100
You entered
abc3.145
You entered
9 9 9
You entered
2.5
You entered
70
-100.
0.
9.
2.
Mathematical Functions
Prototype
Description
acos()
double acos(double x)
Returns the arccosine of its argument. The argument must be in the range -1 <=
x <= 1, and the return value is in the range 0 <= acos <= p.
asin()
double asin(double x)
Returns the arcsine of its argument. The argument must be in the range -1 <= x
<= 1, and the return value is in the range -p/2 <= asin <= p/2.
atan()
double atan(double x)
Returns the arctangent of its argument. The return value is in the range -p/2 <=
atan <= p/2.
atan2()
double atan2(double
x, double y)
Returns the arctangent of x/y. The value returned is in the range -p <= atan2 <=
p.
cos()
double cos(double x)
sin()
double sin(double x)
tan()
double tan(double x)
Prototype
Description
exp()
double exp(double
x)
Returns the natural exponent of its argument, that is, ex where e equals
2.7182818284590452354.
log()
double log(double
x)
Returns the natural logarithm of its argument. The argument must be greater than
0.
log10()
double log10
Returns the base-10 logarithm of its argument. The argument must be greater than
0.
CHAPTER 3
PROGRAMMING IN C: A TUTORIAL
71
Hyperbolic Functions
Function
Prototype
Description
cosh()
double cosh(double x)
sinh()
double sinh(double x)
tanh()
double tanh(double x)
Prototype
Description
sqrt()
double sqrt(double
x)
Returns the square root of its argument. The argument must be zero or greater.
ceil()
double ceil(double
x)
Returns the smallest integer not less than its argument. For example, ceil(4.5)
returns 5.0, and ceil(-4.5) returns -4.0. Although ceil() returns an integer value, it is
returned as a type double.
abs()
int abs(int x)
labs()
long labs(long x)
floor()
double floor(double
x)
Returns the largest integer not greater than its argument. For example, floor(4.5)
returns 4.0, and floor(-4.5) returns -5.0.
modf()
double
modf(double x,
double *y)
Splits x into integral and fractional parts, each with the same sign as x. The
fractional part is returned by the function, and the integral part is assigned to *y.
pow()
double pow(double
x, double y)
Returns xy. An error occurs if x == 0 and y <= 0, or if x < 0 and y is not an integer.
CHAPTER 4
72
If the data structures won't work, it's not helpful at all. Ask yourself what questions the
algorithm will need to be able to ask the data structure, and make sure the data structure
can handle it. If not, then either more data must be added to the structure, or you need to
find a different representation.
Can I code it?
If you don't know or can't remember how to code a given data structure, pick a different
one. Make sure that you have a good idea how each of the operations will affect the
structure of the data.
Another consideration here is memory. Will the data structure fit in the available
memory? If not, compact it or pick a new one. Otherwise, it is already clear from the
beginning that it won't work.
Can I code it in time? or has my programming language support it yet?
As this is a timed contest, you have three to five programs to write in, say, five hours. If
it'll take you an hour and a half to code just the data structure for the first problem, then
you're almost certainly looking at the wrong structure.
Another very important consideration is, whether your programming language has
actually provide you the required data structure. For C++ programmers, STL has a wide
options of a very good built-in data structure, what you need to do is to master them,
rather than trying to built your own data structure.
In contest time, this will be one of the winning strategy. Consider this scenario. All teams
are given a set of problems. Some of them required the usage of 'stack'. The best
programmer from team A directly implement the best known stack implementation, he
need 10 minutes to do so. Surprisingly for them, other teams type in only two lines:
CHAPTER 4
73
"#include <stack>" and "std::stack<int> s;", can you see who have 10 minutes advantage
now?
Can I debug it?
It is easy to forget this particular aspect of data structure selection. Remember that a
program is useless unless it works. Don't forget that debugging time is a large portion of
the contest time, so include its consideration in calculating coding time.
What makes a data structure easy to debug? That is basically determined by the following
two properties.
1. State is easy to examine. The smaller, more compact the representation, in general,
the easier it is to examine. Also, statically allocated arrays are much easier to examine
than linked lists or even dynamically allocated arrays.
2. State can be displayed easily. For the more complex data structures, the easiest way
to examine them is to write a small routine to output the data. Unfortunately, given time
constraints, you'll probably want to limit yourself to text output. This means that
structures like trees and graphs are going to be difficult to examine.
Is it fast?
The usage of more sophisticated data structure will reduce the amount of overall
algorithm complexity. It will be better if you know some advanced data structures.
Things to Avoid: Dynamic Memory
CHAPTER 4
74
element. Sometimes you may have to dynamically allocate these, but as it should only be
done once, it's much easier to get right than allocating and freeing the memory for each
insert and delete.
All of this notwithstanding, sometimes dynamic memory is the way to go, especially for
large data structures where the size of the structure is not known until you have the input.
Things to Avoid: Coolness Factor
Try not to fall into the 'coolness' trap. You may have just seen the neatest data structure,
but remember:
1. Cool ideas that don't work aren't.
2. Cool ideas that'll take forever to code aren't, either
It's much more important that your data structure and program work than how impressive
your data structure is.
Basic Data Structures
There are five basic data structures: arrays, linked lists, stacks, queues, and deque
(pronounced deck, a double ended queue). It will not be discussed in this section, go for
their respective section.
Arrays
Array is the most useful data structures, in fact, this data structure will almost always
used in all contest problems.Lets look at the good side first: if index is known, searching
an element in an array is very fast, O(1), this good for looping/iteration. Array can also be
used to implement other sophisticated data structures such as stacks, queues, hash
tables.However, being the easiest data structure doesn't mean that array is efficient. In
some cases array can be very inefficient. Moreover, in standard array, the size is fixed. If
you don't know the input size beforehand, it may be wiser to use vector (a resizable
array). Array also suffer a very slow insertion in ordered array, another slow searching in
unordered array, and unavoidable slow deletion because you have to shift all elements.
Search
Insertion
O(n/2) comparisons
No comparison, O(1)
Deletion
O(n) comparisons
No comparisons, O(1)
O(n) comparisons
more than O(n/2) moves
CHAPTER 4
75
We commonly use one-dimensional array for standard use and two-dimensional array to
represent matrices, board, or anything that two-dimensional. Three-dimensional is rarely
used to model 3D situations.
Row major, cache-friendly, use this method to access all items in array sequentially.
for (i=0; i<numRow; i++)
// ROW FIRST = EFFECTIVE
for (j=0; j<numCol; j++)
array[i][j] = 0;
Column major, NOT cache-friendly, DO NOT use this method or you'll get very poor
performance. Why? you will learn this in Computer Architecture course. For now, just
take note that computer access array data in row major.
for (j=0; j<numCol; j++)
// COLUMN FIRST = INEFFECTIVE
for (i=0; i<numRow; i++)
array[i][j] = 0;
Static array has a drawback when the size of input is not known beforehand. If that is the
case, you may want to consider vector, a resizable array.
There are other data structures which offer much more efficient resizing capability such
as Linked List, etc.
TIPS: UTILIZING C++ VECTOR STL
C++ STL has vector template for you.
#include <stdio.h>
#include <vector>
#include <algorithm>
using namespace std;
void main() {
// just do this, write vector<the type you want,
// in this case, integer> and the vector name
vector<int> v;
// try inserting 7 different integers, not ordered
v.push_back(3); v.push_back(1); v.push_back(2);
v.push_back(7); v.push_back(6); v.push_back(5);
v.push_back(4);
CHAPTER 4
76
Linked List
Motivation for using linked list: Array is static and even though it has O(1) access time if
index is known, Array must shift its elements if an item is going to be inserted or deleted
and this is absolutely inefficient. Array cannot be resized if it is full (see resizable array vector for the trick but slow resizable array).
Linked list can have a very fast insertion and deletion. The physical location of data in
linked list can be anywhere in the memory but each node must know which part in
memory is the next item after them.
Linked list can be any big as you wish as long there is sufficient memory. The side effect
of Linked list is there will be wasted memory when a node is "deleted" (only flagged as
deleted). This wasted memory will only be freed up when garbage collector doing its
action (depends on compiler / Operating System used).
Linked list is a data structure that is commonly used because of it's dynamic feature.
Linked list is not used for fun, it's very complicated and have a tendency to create run
time memory access error). Some programming languages such as Java and C++ actually
support Linked list implementation through API (Application Programming Interface)
and STL (Standard Template Library).
Linked list is composed of a data (and sometimes pointer to the data) and a pointer to next
item. In Linked list, you can only find an item through complete search from head until it
found the item or until tail (not found). This is the bad side for Linked list, especially for a
very long list. And for insertion in Ordered Linked List, we have to search for appropriate
place using Complete Search method, and this is slow too. (There are some tricks to
improve searching in Linked List, such as remembering references to specific nodes, etc).
CHAPTER 4
77
CHAPTER 4
78
Stack
A data structures which only allow insertion (push) and deletion (pop) from the top only.
This behavior is called Last In First Out (LIFO), similar to normal stack in the real world.
Important stack operations
1. Push (C++ STL: push())
Adds new item at the top of the stack.
2. Pop (C++ STL: pop())
Retrieves and removes the top of a stack.
3. Peek (C++ STL: top())
Retrieves the top of a stack without deleting it.
4. IsEmpty (C++ STL: empty())
Determines whether a stack is empty.
Some stack applications
1. To model "real stack" in computer world: Recursion, Procedure Calling, etc.
2. Checking palindrome (although checking palindrome using Queue & Stack is 'stupid').
3. To read an input from keyboard in text editing with backspace key.
4. To reverse input data, (another stupid idea to use stack for reversing data).
5. Checking balanced parentheses.
6. Postfix calculation.
7. Converting mathematical expressions. Prefix, Infix, or Postfix.
CHAPTER 4
79
Queue
A data structures which only allow insertion from the back (rear), and only allow deletion
from the head (front). This behavior is called First In First Out (FIFO), similar to normal
queue in the real world.
Important queue operations:
1. Enqueue (C++ STL: push())
Adds new item at the back (rear) of a queue.
2. Dequeue (C++ STL: pop())
CHAPTER 4
Retrieves and removes the front of a queue at the back (rear) of a queue.
3. Peek (C++ STL: top())
Retrieves the front of a queue without deleting it.
4. IsEmpty (C++ STL: empty())
Determines whether a queue is empty.
TIPS: UTILIZING C++ QUEUE STL
Standard queue is also not difficult to implement. Again, why trouble
yourself, just use C++ queue STL.
#include <stdio.h>
#include <queue>
// use this to avoid specifying "std::" everywhere
using namespace std;
void main() {
// just do this, write queue<the type you want,
// in this case, integer> and the queue name
queue<int> q;
// try inserting 7 different integers, not ordered
q.push(3); q.push(1); q.push(2);
q.push(7); q.push(6); q.push(5);
q.push(4);
// the item that is inserted first will come out first
// First In First Out (FIFO) order...
while (!q.empty()) {
// notice that this is not "top()" !!!
printf("%d ",q.front());
q.pop();
}
printf("\n");}
80
CHAPTER 5
INPUT/OUTPUT TECHNIQUES
81
There are N lines, each lines always start with character '0' followed by '.', then unknown
number of digits x, finally the line always terminated by three dots "...".
N
0.xxxx...
void main() {
scanf("%d",&N);
for (i=0; i<N; i++) {
scanf("0.%[0-9]...",&digits); // surprised?
printf("the digits are 0.%s\n",digits);
}
}
This is the trick that many C/C++ programmers doesn't aware of. Why we said C++ while
scanf/printf is a standard C I/O routines? This is because many C++ programmers
CHAPTER 5
INPUT/OUTPUT TECHNIQUES
82
"forcing" themselves to use cin/cout all the time, without realizing that scanf/printf can
still be used inside all C++ programs.
Mastery of programming language I/O routines will help you a lot in programming
contests.
Advanced use of printf() and scanf()
Those who have forgotten the advanced use of printf() and scanf(), recall the following
examples:
scanf("%[ABCDEFGHIJKLMNOPQRSTUVWXYZ]",&line); //line is a string
This scanf() function takes only uppercase letters as input to line and any other characters
other than A..Z terminates the string. Similarly the following scanf() will behave like
gets():
scanf("%[^\n]",line); //line is a string
Learn the default terminating characters for scanf(). Try to read all the advanced features of
scanf() and printf(). This will help you in the long run.
Using new line with scanf()
And the following program is executed to take input from the file:
char input[100],ch;
void main(void)
{
freopen("input.txt","rb",stdin);
scanf("%s",&input);
scanf("%c",&ch);
}
CHAPTER 5
INPUT/OUTPUT TECHNIQUES
83
What will be their value now? The value of ch will be '\n' for the first code and 'd' for the
second code.
Be careful about using gets() and scanf() together !
You should also be careful about using gets() and scanf() in the same program. Test it with
the following scenario. The code is:
scanf("%s\n",&dummy);
gets(name);
What do you get as the value of name? "XXX" or "bbbbbXXX" (Here, "b" means blank or
space)
Multiple input programs
"Multiple input programs" are an invention of the online judge. The online judge often uses
the problems and data that were first presented in live contests. Many solutions to problems
presented in live contests take a single set of data, give the output for it, and terminate. This
does not imply that the judges will give only a single set of data. The judges actually give
multiple files as input one after another and compare the corresponding output files with
the judge output. However, the Valladolid online judge gives only one file as input. It
inserts all the judge inputs into a single file and at the top of that file, it writes how many
sets of inputs there are. This number is the same as the number of input files the contest
judges used. A blank line now separates each set of data. So the structure of the input file
for multiple input program becomes:
CHAPTER 5
INPUT/OUTPUT TECHNIQUES
84
Integer N
//denoting the number of sets of input
--blank line--input set 1 //As described in the problem statement
--blank line--input set 2 //As described in the problem statement
--blank line--input set 3 //As described in the problem statement
--blank line--.
.
.
--blank line--input set n //As described in the problem statement
--end of file--
Note that there should be no blank after the last set of data. The structure of the output file
for a multiple input program becomes:
Output for set 1
--Blank line--Output for set 2
--Blank line--Output for set 3
--Blank line--.
.
.
--blank line--Output for set n
--end of file--
The USU online judge does not have multiple input programs like Valladolid. It prefers to
give multiple files as input and sets a time limit for each set of input.
Problems of multiple input programs
There are some issues that you should consider differently for multiple input programs.
Even if the input specification says that the input terminates with the end of file (EOF),
each set of input is actually terminated by a blank line, except for the last one, which is
terminated by the end of file. Also, be careful about the initialization of variables. If they
are not properly initialized, your program may work for a single set of data but give correct
output for multiple sets of data. All global variables are initialized to their corresponding
zeros. [6]
CHAPTER 6
85
You are given N lamps and four switches. The first switch toggles all lamps, the
second the even lamps, the third the odd lamps, and last switch toggles lamps
1,4,7,10,...
Given the number of lamps, N, the number of button presses made (up to 10,000),
and the state of some of the lamps (e.g., lamp 7 is off), output all the possible states
the lamps could be in.
Naively, for each button press, you have to try 4 possibilities, for a total of 4^10000
(about 10^6020), which means there's no way you could do complete search (this
particular algorithm would exploit recursion).
Noticing that the order of the button presses does not matter gets this number down to
about 10000^4 (about 10^16), still too big to completely search (but certainly closer by a
factor of over 10^6000).
However, pressing a button twice is the same as pressing the button no times, so all you
really have to check is pressing each button either 0 or 1 times. That's only 2^4 = 16
possibilities, surely a number of iterations solvable within the time limit.
The Clocks
A group of nine clocks inhabits a 3 x 3 grid; each is set to 12:00, 3:00, 6:00, or 9:00.
Your goal is to manipulate them all to read 12:00. Unfortunately, the only way you
can manipulate the clocks is by one of nine different types of move, each one of
which rotates a certain subset of the clocks 90 degrees clockwise. Find the shortest
sequence of moves which returns all the clocks to 12:00.
CHAPTER 6
86
The 'obvious' thing to do is a recursive solution, which checks to see if there is a solution
of 1 move, 2 moves, etc. until it finds a solution. This would take 9^k time, where k is the
number of moves. Since k might be fairly large, this is not going to run with reasonable
time constraints.
Note that the order of the moves does not matter. This reduces the time down to k^9,
which isn't enough of an improvement.
However, since doing each move 4 times is the same as doing it no times, you know that
no move will be done more than 3 times. Thus, there are only 49 possibilities, which is
only 262,072, which, given the rule of thumb for run-time of more than 10,000,000
operations in a second, should work in time. The brute-force solution, given this insight,
is perfectly adequate.
It is beautiful, isn't it? If you have this kind of reasoning ability. Many seemingly hard
problems is eventually solvable using brute force.
Recursion
CHAPTER 6
87
Recursion is a powerful and elegant technique that can be used to solve a problem by
solving a smaller problem of the same type. Many problems in Computer Science involve
recursion and some of them are naturally recursive.
If one problem can be solved in both way (recursive or iterative), then choosing iterative
version is a good idea since it is faster and doesn't consume a lot of memory. Examples:
Factorial, Fibonacci, etc.
However, there are also problems that are can only be solved in recursive way or more
efficient in recursive type or when it's iterative solutions are difficult to conceptualize.
Examples: Tower of Hanoi, Searching (DFS, BFS), etc.
Types of recursion
There are 2 types of recursion, Linear recursion and multiple branch (Tree) recursion.
1. Linear recursion is a recursion whose order of growth is linear (not branched).
Example of Linear recursion is Factorial, defined by fac (n)=n * fac (n-1).
2. Tree recursion will branch to more than one node each step, growing up very quickly. It
provides us a flexible ways to solve some logically difficult problem. It can be used to
perform a Complete Search (To make the computer to do the trial and error). This
recursion type has a quadratic or cubic or more order of growth and therefore, it is not
suitable for solving "big" problems. It's limited to small. Examples: solving Tower of
Hanoi, Searching (DFS, BFS), Fibonacci number, etc.
Some compilers can make some type of recursion to be iterative. One example is tailrecursion elimination. Tail-recursive is a type of recursive which the recursive call is the
last command in that function/procedure. This
Tips on Recursion
CHAPTER 6
88
This technique use analogy "smaller is simpler". Divide and conquer algorithms try to
make problems simpler by dividing it to sub problems that can be solved easier than the
main problem and then later it combine the results to produce a complete solution for the
main problem.
Divide and Conquer algorithms: Quick Sort, Merge Sort, Binary Search.
Divide & Conquer has 3 main steps:
Binary Search, is not actually follow the pattern of the full version of Divide & Conquer,
since it never combine the sub problems solution anyway. However, lets use this example
to illustrate the capability of this technique.
Binary Search will help you find an item in an array. The naive version is to scan through
the array one by one (sequential search). Stopping when we found the item (success) or
when we reach the end of array (failure). This is the simplest and the most inefficient way
CHAPTER 6
89
to find an element in an array. However, you will usually end up using this method
because not every array is ordered, you need sorting algorithm to sort them first.
Binary search algorithm is using Divide and Conquer approach to reduce search space
and stop when it found the item or when search space is empty.
Pre-requisite to use binary search is the array must be an ordered array, the most
commonly used example of ordered array for binary search is searching an item in a
dictionary.
Efficiency of binary search is O(log n). This algorithm was named "binary" because it's
behavior is to divide search space into 2 (binary) smaller parts).
Optimizing your source code
Your code must be fast. If it cannot be "fast", then it must at least "fast enough". If time
limit is 1 minute and your currently program run in 1 minute 10 seconds, you may want to
tweak here and there rather than overhaul the whole code again.
Generating vs Filtering
Programs that generate lots of possible answers and then choose the ones that are correct
(imagine an 8-queen solver) are filters. Those that hone in exactly on the correct answer
without any false starts are generators. Generally, filters are easier (faster) to code and run
slower. Do the math to see if a filter is good enough or if you need to try and create a
generator.
Pre-Computation / Pre-Calculation
Sometimes it is helpful to generate tables or other data structures that enable the fastest
possible lookup of a result. This is called Pre-Computation (in which one trades space for
time). One might either compile Pre-Computed data into a program, calculate it when the
program starts, or just remember results as you compute them. A program that must
translate letters from upper to lower case when they are in upper case can do a very fast
table lookup that requires no conditionals, for example. Contest problems often use prime
numbers - many times it is practical to generate a long list of primes for use elsewhere in
a program.
Decomposition
While there are fewer than 20 basic algorithms used in contest problems, the challenge of
combination problems that require a combination of two algorithms for solution is
CHAPTER 6
90
daunting. Try to separate the cues from different parts of the problem so that you can
combine one algorithm with a loop or with another algorithm to solve different parts of
the problem independently. Note that sometimes you can use the same algorithm twice on
different (independent!) parts of your data to significantly improve your running time.
Symmetries
Many problems have symmetries (e.g., distance between a pair of points is often the same
either way you traverse the points). Symmetries can be 2-way, 4-way, 8-way, and more.
Try to exploit symmetries to reduce execution time.
For instance, with 4-way symmetry, you solve only one fourth of the problem and then
write down the four solutions that share symmetry with the single answer (look out for
self-symmetric solutions which should only be output once or twice, of course).
Solving forward vs backward
Surprisingly, many contest problems work far better when solved backwards than when
using a frontal attack. Be on the lookout for processing data in reverse order or building
an attack that looks at the data in some order or fashion other than the obvious.
CHAPTER 7
MATHEMATICS
91
CHAPTER 7 MATHEMATICS
Base Number Conversion
Decimal is our most familiar base number, whereas computers are very familiar with
binary numbers (octal and hexa too). The ability to convert between bases is important.
[2]
Refer to mathematics book for this.
TEST YOUR BASE CONVERSION KNOWLEDGE
Solve UVa problems related with base conversion:
343 - What Base Is This?
353 - The Bases Are Loaded
389 - Basically Speaking
Big Mod
This formula is used in several algorithm such as in Fermat Little Test for primality
testing:
R = B^P mod M (B^P is a very very big number). By using the formula, we can get the
correct answer without being afraid of overflow.
This is how to calculate R quickly (using Divide & Conquer approach, see exponentiation
below for more details):
CHAPTER 7
MATHEMATICS
92
Big Integer
Long time ago, 16-bit integer is sufficient: [-215 to 215-1] ~ [-32,768 to 32,767].
When 32-bit machines are getting popular, 32-bit integers become necessary. This data
type can hold range from [-231 to 231-1] ~ [2,147,483,648 to 2,147,483,647]. Any integer
with 9 or less digits can be safely computed using this data type. If you somehow must
use the 10th digit, be careful of overflow.
But man is very greedy, 64-bit integers are created, referred as programmers as long long
data type or Int64 data type. It has an awesome range up that can covers 18 digits integers
fully, plus the 19th digit partially [-263-1 to 263-1] ~ [9,223,372,036,854,775,808 to
9,223,372,036,854,775,807]. Practically this data type is safe to compute most of standard
arithmetic problems, except some problems.
Note: for those who don't know, in C, long long n is read using: scanf("%lld",&n); and unsigned long long n is read using:
scanf("%llu",&n); For 64 bit data: typedef unsigned long long int64; int64 test_data=64000000000LL
Now, RSA cryptography need 256 bits of number or more.This is necessary, human
always want more security right? However, some problem setters in programming
contests also follow this trend. Simple problem such as finding n'th factorial will become
very very hard once the values exceed 64-bit integer data type. Yes, long double can store
very high numbers, but it actually only stores first few digits and an exponent, long
double is not precise.
Implement your own arbitrary precision arithmetic algorithm Standard pen and pencil
algorithm taught in elementary school will be your tool to implement basic arithmetic
operations: addition, subtraction, multiplication and division. More sophisticated
CHAPTER 7
MATHEMATICS
93
algorithm are available to enhance the speed of multiplication and division. Things are
getting very complicated now.
TEST YOUR BIG INTEGER KNOWLEDGE
Solve UVa problems related with Big Integer:
485 - Pascal Triangle of Death
495 - Fibonacci Freeze - plus Fibonacci
10007 - Count the Trees - plus Catalan formula
10183 - How Many Fibs - plus Fibonacci
10219 - Find the Ways ! - plus Catalan formula
10220 - I Love Big Numbers ! - plus Catalan formula
10303 - How Many Trees? - plus Catalan formula
10334 - Ray Through Glasses - plus Fibonacci
10519 - !!Really Strange!!
10579 - Fibonacci Numbers - plus Fibonacci
Carmichael Number
Carmichael number is a number which is not prime but has >= 3 prime factors
You can compute them using prime number generator and prime factoring algorithm.
The first 15 Carmichael numbers are:
561,1105,1729,2465,2821,6601,8911,10585,15841,29341,41041,46657,52633,6274
5,63973
Catalan Formula
The number of distinct binary trees can be generalized as Catalan formula, denoted as
C(n).
C(n) = 2n C n / (n+1)
If you are asked values of several C(n), it may be a good choice to compute the values
bottom up.
CHAPTER 7
MATHEMATICS
94
C(N,K) means how many ways that N things can be taken K at a time.
This can be a great challenge when N and/or K become very large.
Combination of (N,K) is defined as:
N!
---------(N-K)!*K!
CHAPTER 7
MATHEMATICS
95
93,326,215,443,944,152,681,699,238,856,266,700,490,715,968,264,381,621,46
8,592,963,895,217,599,993,229,915,608,941,463,976,156,518,286,253,697,920
,827,223,758,251,185,210,916,864,000,000,000,000,000,000,000,000
So, how to compute the values of C(N,K) when N and/or K is big but the result is
guaranteed to fit in 32-bit integer?
Divide by GCD before multiply (sample code in C)
long gcd(long a,long b) {
if (a%b==0) return b; else return gcd(b,a%b);
}
void Divbygcd(long& a,long& b) {
long g=gcd(a,b);
a/=g;
b/=g;
}
long C(int n,int k){
long numerator=1,denominator=1,toMul,toDiv,i;
if (k>n/2) k=n-k; /* use smaller k */
for (i=k;i;i--) {
toMul=n-k+i;
toDiv=i;
Divbygcd(toMul,toDiv);
/* always divide before multiply */
Divbygcd(numerator,toDiv);
Divbygcd(toMul,denominator);
numerator*=toMul;
denominator*=toDiv;
}
return numerator/denominator;
}
If d is a divisor of n, then so is n/d, but d & n/d cannot both be greater than sqrt(n).
2 is a divisor of 6, so 6/2 = 3 is also a divisor of 6
CHAPTER 7
MATHEMATICS
96
Exponentiation
This is 'slow', especially when power is big - O(n) time. It's better to use divide &
conquer.
Divide & Conquer exponentiation
long square(long n) { return n*n; }
long fastexp(long base,long power) {
if (power == 0)
return 1;
else if (power%2 == 0)
return square(fastexp(base,power/2));
else
return base * (fastexp(base,power-1));
}
CHAPTER 7
MATHEMATICS
97
Factorial
=
=
=
=
=
3
3
3
3
6
*
*
*
*
Fac(2)
2 * Fac(1)
2 * 1 * Fac(0)
2 * 1 * 1
CHAPTER 7
MATHEMATICS
98
CHAPTER 7
MATHEMATICS
99
As it name suggest, Greatest Common Divisor (GCD) algorithm finds the greatest
common divisor between two number a and b. GCD is a very useful technique, for
example to reduce rational numbers into its smallest version (3/6 = 1/2).The best GCD
algorithm so far is Euclid's Algorithm. Euclid found this interesting mathematical
equality. GCD(a,b) = GCD (b,(a mod b)). Here is the fastest implementation of GCD
algorithm
int GCD(int a,int b) {
while (b > 0) {
a = a % b;
a ^= b;
b ^= a;
}
a ^= b;
return a;
Lowest Common Multiple and Greatest Common Divisor (GCD) are two important
number properties, and they are interrelated. Even though GCD is more often used than
LCM, it is useful to learn LCM too.
LCM (m,n) = (m * n) / GCD (m,n)
LCM (3,2) = (3 * 2) / GCD (3,2)
LCM (3,2) = 6 / 1
LCM (3,2) = 6
Application of LCM -> to find a synchronization time between two traffic light, if traffic
light A display green color every 3 minutes and traffic light B display green color every 2
minutes, then every 6 minutes, both traffic light will display green color at the same time.
Mathematical Expressions
There are three types of mathematical/algebraic expressions. They are Infix, Prefix, &
Postfix expressions.
Infix expression grammar:
<infix> = <identifier> | <infix><operator><infix>
<operator> = + | - | * | / <identifier> = a | b | .... | z
Infix expression example: (1 + 2) => 3, the operator is in the middle of two operands.
Infix expression is the normal way human compute numbers.
CHAPTER 7
MATHEMATICS
100
Computer do postfix calculation better than infix calculation. Therefore when you
compile your program, the compiler will convert your infix expressions (most
programming language use infix) into postfix, the computer-friendly version.
Why do computer like Postfix better than Infix?
It's because computer use stack data structure, and postfix calculation can be done easily
using stack.
Infix to Postfix conversion
To use this very efficient Postfix calculation, we need to convert our Infix expression into
Postfix. This is how we do it:
Example:
Infix statement: ( ( 4 - ( 1 + 2 * ( 6 / 3 ) - 5 ) ) ). This is what the algorithm will do, look
carefully at the steps.
Expression
((4-(1+2*(6/3)-5)))
((4-(1+2*(6/3)-5)))
((4-(1+2*(6/3)-5)))
((4-(1+2*(6/3)-5)))
Postfix expression
4
4
CHAPTER 7
MATHEMATICS
((4-(1+2*(6/3)-5)))
((4-(1+2*(6/3)-5)))
((4-(1+2*(6/3)-5)))
((4-(1+2*(6/3)-5)))
((4-(1+2*(6/3)-5)))
((4-(1+2*(6/3)-5)))
((4-(1+2*(6/3)-5)))
((4-(1+2*(6/3)-5)))
((4-(1+2*(6/3)-5)))
((4-(1+2*(6/3)-5)))
((4-(1+2*(6/3)-5)))
((4-(1+2*(6/3)-5)))
((4-(1+2*(6/3)-5)))
((4-(1+2*(6/3)-5)))
((4-(1+2*(6/3)-5)))
((-(
((-(
((-(+
((-(+
((-(+*
((-(+*(
((-(+*(
((-(+*(/
((-(+*(/
((-(+*
((-(((-((((
101
4
41
41
412
412
412
4126
4126
41263
41263/
41263/*+
41263/*+5
41263/*+541263/*+5-41263/*+5--
Prime Factors
N
\
100
/ \
2 50
/ \
2 25
/ \
5 5
/ \
5 1
Standard way
Generate a prime list again, and then check how many of those primes can divide n.This
is very slow. Maybe you can write a very efficient code using this algorithm, but there is
another algorithm that is much more effective than this.
CHAPTER 7
MATHEMATICS
102
Prime Numbers
Prime numbers are important in Computer Science (For example: Cryptography) and
finding prime numbers in a given interval is a "tedious" task. Usually, we are looking for
big (very big) prime numbers therefore searching for a better prime numbers algorithms
will never stop.
1. Standard prime testing
int is_prime(int n) {
for (int i=2; i<=(int) sqrt(n); i++) if (n%i == 0) return 0;
return 1;
}void main() {
int i,count=0;
for (i=1; i<10000; i++) count += is_prime(i);
printf("Total of %d primes\n",count);
}
CHAPTER 7
MATHEMATICS
103
3. Restatement of sqrt.
int is_prime(int n) {
for (int i=2; i*i<=n; i++) if (n%i == 0) return 0;
return 1;
}
//
//
//
//
//
1 is NOT a prime
2 is a prime
NO prime is EVEN, except 2
start from 3, jump 2 numbers
no need to check even numbers
CHAPTER 7
MATHEMATICS
104
How to do this ?
This is a probabilistic algorithm so you cannot guarantee the possibility of getting correct
answer. In a range as big as 1-1000000, Fermat Little Test can be fooled by (only) 255
Carmichael numbers (numbers that can fool Fermat Little Test, see Carmichael numbers
above). However, you can do multiple random checks to increase this probability.
Fermat Algorithm
If 2^N modulo N = 2 then N has a high probability to be a prime number.
Example:
let N=3 (we know that 3 is a prime).
2^3 mod 3 = 8 mod 3 = 2, then N has a high probability to be a prime number... and in
fact, it is really prime.
Another example:
let N=11 (we know that 11 is a prime).
2^11 mod 11 = 2048 mod 11 = 2, then N has a high probability to be a prime number...
again, this is also really prime.
CHAPTER 7
MATHEMATICS
105
Sieve of Eratosthenes:
Sieve is the best prime generator algorithm. It will generate a list of primes very quickly,
but it will need a very big memory. You can use Boolean flags to do this (Boolean is only
1 byte).
Algorithm for Sieve of Eratosthenes to find the prime numbers within a range L,U
(inclusive), where must be L<=U.
void sieve(int L,int U) {
int i,j,d;
d=U-L+1; /* from range L to U, we have d=U-L+1 numbers. */
/* use flag[i] to mark whether (L+i) is a prime number or not. */
bool *flag=new bool[d];
for (i=0;i<d;i++) flag[i]=true; /* default: mark all to be true */
for (i=(L%2!=0);i<d;i+=2) flag[i]=false;
CHAPTER 8
SORTING
106
CHAPTER 8 SORTING
Definition of a sorting problem
These are the difficulties in sorting that can also happen in real life:
A. Size of the list to be ordered is the main concern. Sometimes, the computer emory
is not sufficient to store all data. You may only be able to hold part of the data
inside the computer at any time, the rest will probably have to stay on disc or
tape. This is known as the problem of external sorting. However, rest assured,
that almost all programming contests problem size will never be extremely big
such that you need to access disc or tape to perform external sorting... (such
hardware access is usually forbidden during contests).
B. Another problem is the stability of the sorting method. Example: suppose you are
an airline. You have a list of the passengers for the day's flights. Associated to
each passenger is the number of his/her flight. You will probably want to sort the
list into alphabetical order. No problem... Then, you want to re-sort the list by
flight number so as to get lists of passengers for each flight. Again, "no
problem"... - except that it would be very nice if, for each flight list, the names
were still in alphabetical order. This is the problem of stable sorting.
C. To be a bit more mathematical about it, suppose we have a list of items {xi} with
xa equal to xb as far as the sorting comparison is concerned and with xa before xb
in the list. The sorting method is stable if xa is sure to come before xb in the sorted
list.
Finally, we have the problem of key sorting. The individual items to be sorted might be
very large objects (e.g. complicated record cards). All sorting methods naturally involve a
lot of moving around of the things being sorted. If the things are very large this might
take up a lot of computing time -- much more than that taken just to switch two integers
in an array.
Comparison-based sorting algorithms
CHAPTER 8
SORTING
107
than. These sorting algorithms are dealing with how to use this comparison effectively, so
that we minimize the amount of such comparison. Lets start from the most naive version
to the most sophisticated comparison-based sorting algorithms.
Bubble Sort
BubbleSort(A)
for i <- length[A]-1 down to 1
for j <- 0 to i-1
if (A[j] > A[j+1]) // change ">" to "<" to do a descending sort
temp <- A[j]
A[j] <- A[j+1]
A[j+1] <- temp
CHAPTER 8
SORTING
108
Quick Sort
The only thing that you need to implement is the compare_function, which takes in two
arguments of type "const void", which can be cast to appropriate data structure, and then
return one of these three values:
negative, if a should be before b
0, if a equal to b
positive, if a should be after b
CHAPTER 8
SORTING
109
CHAPTER 8
SORTING
110
05
05
12
01
1982
1980
1999
0001
Sunny
Cecilia
End of 20th century
Start of modern calendar
01
05
05
12
0001
1980
1982
1999
To do multi field sorting like this, traditionally one will choose multiple sort using sorting
algorithm which has "stable-sort" property.
The better way to do multi field sorting is to modify the compare_function in such a way
that you break ties accordingly... I'll give you an example using birthday list again.
typedef struct {
int day,month,year;
char *name;
} birthday;
int compare_function(const void *a,const void *b) {
birthday *x = (birthday *) a;
birthday *y = (birthday *) b;
if (x->month != y->month) // months different
return x->month - y->month; // sort by month
CHAPTER 8
SORTING
111
Linear-time Sorting
CHAPTER 8
SORTING
112
113
622
sort by third (last) digit:
321
622
113
257
after this phase, the third (last) digit is sorted.
sort by second digit:
113
321
622
257
after this phase, the second and third (last) digit are sorted.
sort by second digit:
113
257
321
622
after this phase, all digits are sorted.
For a set of n d-digits numbers, we will do d pass of counting sort which have complexity
O(n+k), therefore, the complexity of Radix Sort is O(d(n+k)).
CHAPTER 9
SEARCHING
113
CHAPTER 9 SEARCHING
Searching is very important in computer science. It is very closely related to sorting. We
usually search after sorting the data. Remember Binary Search? This is the best example
[2]
of an algorithm which utilizes both Sorting and Searching.
Search algorithm depends on the data structure used. If we want to search a graph, then
we have a set of well known algorithms such as DFS, BFS, etc
Binary Search
The most common application of binary search is to find a specific value in a sorted list.
The search begins by examining the value in the center of the list; because the values are
sorted, it then knows whether the value occurs before or after the center value, and
searches through the correct half in the same way. Here is simple pseudocode which
determines the index of a given value in a sorted list a between indices left and right:
function binarySearch(a, value, left, right)
if right < left
return not found
mid := floor((left+right)/2)
if a[mid] = value
return mid
if value < a[mid]
binarySearch(a, value, left, mid-1)
else
binarySearch(a, value, mid+1, right)
In both cases, the algorithm terminates because on each recursive call or iteration, the
range of indexes right minus left always gets smaller, and so must eventually become
negative.
Binary search is a logarithmic algorithm and executes in O(log n) time. Specifically, 1 +
log2N iterations are needed to return an answer. It is considerably faster than a linear
search. It can be implemented using recursion or iteration, as shown above, although in
many languages it is more elegantly expressed recursively.
Binary Search Tree
Binary Search Tree (BST) enable you to search a collection of objects (each with a real or
integer value) quickly to determine if a given value exists in the collection.
CHAPTER 9
SEARCHING
114
Basically, a binary search tree is a node-weighted, rooted binary ordered tree. That
collection of adjectives means that each node in the tree might have no child, one left
child, one right child, or both left and right child. In addition, each node has an object
associated with it, and the weight of the node is the value of the object.
The binary search tree also has the property that each
node's left child and descendants of its left child have a
value less than that of the node, and each node's right child
and its descendants have a value greater or equal to it.
Binary Search Tree
The nodes are generally represented as a structure with
four fields, a pointer to the node's left child, a pointer to
the node's right child, the weight of the object stored at
this node, and a pointer to the object itself. Sometimes, for
easier access, people add pointer to the parent too.
Why are Binary Search Tree useful?
Given a collection of n objects, a binary search tree takes only O(height) time to find an
objects, assuming that the tree is not really poor (unbalanced), O(height) is O(log n). In
addition, unlike just keeping a sorted array, inserting and deleting objects only takes
O(log n) time as well. You also can get all the keys in a Binary Search Tree in a sorted
order by traversing it using O(n) inorder traversal.
Variations on Binary Trees
There are several variants that ensure that the trees are never poor. Splay trees, Red-black
trees, B-trees, and AVL trees are some of the more common examples. They are all much
more complicated to code, and random trees are generally good, so it's generally not
worth it.
Tips: If you're concerned that the tree you created might be bad (it's being created by
inserting elements from an input file, for example), then randomly order the elements
before insertion.
Dictionary
A dictionary, or hash table, stores data with a very quick way to do lookups. Let's say
there is a collection of objects and a data structure must quickly answer the question: 'Is
CHAPTER 9
SEARCHING
115
this object in the data structure?' (e.g., is this word in the dictionary?). A hash table does
this in less time than it takes to do binary search.
The idea is this: find a function that maps the elements of the collection to an integer
between 1 and x (where x, in this explanation, is larger than the number of elements in
your collection). Keep an array indexed from 1 to x, and store each element at the
position that the function evaluates the element as. Then, to determine if something is in
your collection, just plug it into the function and see whether or not that position is
empty. If it is not check the element there to see if it is the same as the something you're
holding,
For example, presume the function is defined over 3-character words, and is (first letter +
(second letter * 3) + (third letter * 7)) mod 11 (A=1, B=2, etc.), and the words are 'CAT',
'CAR', and 'COB'. When using ASCII, this function takes 'CAT' and maps it to 3, maps
'CAR' to 0, and maps 'COB' to 7, so the hash table would look like this:
0: CAR
1
2
3: CAT
4
5
6
7: COB
8
9
10
Now, to see if 'BAT' is in there, plug it into the hash function to get 2. This position in the
hash table is empty, so it is not in the collection. 'ACT', on the other hand, returns the
value 7, so the program must check to see if that entry, 'COB', is the same as 'ACT' (no,
so 'ACT' is not in the dictionary either). In the other hand, if the search input is 'CAR',
'CAT', 'COB', the dictionary will return true.
Collision Handling
This glossed over a slight problem that arises. What can be done if two entries map to the
same value (e.g.,we wanted to add 'ACT' and 'COB')? This is called a collision. There are
couple ways to correct collisions, but this document will focus on one method, called
chaining.
Instead of having one entry at each position, maintain a linked list of entries with the
same hash value. Thus, whenever an element is added, find its position and add it to the
CHAPTER 9
SEARCHING
116
beginning (or tail) of that list. Thus, to have both 'ACT' and 'COB' in the table, it would
look something like this:
0: CAR
1
2
3: CAT
4
5
6
7: COB -> ACT
8
9
10
Now, to check an entry, all elements in the linked list must be examined to find out the
element is not in the collection. This, of course, decreases the efficiency of using the hash
table, but it's often quite handy.
Hash Table variations
It is often quite useful to store more information that just the value. One example is when
searching a small subset of a large subset, and using the hash table to store locations
visited, you may want the value for searching a location in the hash table with it.
CHAPTER 10
GREEDY ALGORITHMS
117
A selection function, which chooses the best candidate to be added to the solution
There is a long list of stalls, some of which need to be covered with boards. You can use
up to N (1 <= N <= 50) boards, each of which may cover any number of consecutive
stalls. Cover all the necessary stalls, while covering as few total stalls as possible. How
will you solve it?
CHAPTER 10
GREEDY ALGORITHMS
118
The basic idea behind greedy algorithms is to build large solutions up from smaller ones.
Unlike other approaches, however, greedy algorithms keep only the best solution they
find as they go along. Thus, for the sample problem, to build the answer for N = 5, they
find the best solution for N = 4, and then alter it to get a solution for N = 5. No other
solution for N = 4 is ever considered.
Greedy algorithms are fast, generally linear to quadratic and require little extra memory.
Unfortunately, they usually aren't correct. But when they do work, they are often easy to
implement and fast enough to execute.
Problems with Greedy algorithms
CHAPTER 10
GREEDY ALGORITHMS
119
If the answer doesn't contain this particular gap but does contain another gap which is just
as large, doing the same transformation yields an answer which uses as many boards and
covers as many stalls as the other answer. This new answer is just as good as the original
solution but no better, so we may choose either.
Thus, there exists an optimal answer which contains the large gap, so at each step, there
is always an optimal answer which is a superset of the current state. Thus, the final
answer is optimal.
If a greedy solution exists, use it. They are easy to code, easy to debug, run quickly, and
use little memory, basically defining a good algorithm in contest terms. The only missing
element from that list is correctness. If the greedy algorithm finds the correct answer, go
for it, but don't get suckered into thinking the greedy solution will work for all problems.
Sorting a three-valued sequence
Analysis: Obviously, a swap can put at most two elements in place, so all the swaps of
the first type are optimal. Also, it is clear that they use different types of elements, so
there is no ``interference'' between those types. This means the order does not matter.
Once those swaps have been performed, the best you can do is two swaps for every three
elements not in the correct location, which is what the second part will achieve (for
example, all the 1's are put in place but no others; then all that remains are 2's in the 3's
place and vice-versa, and which can be swapped).
Topological Sort
Given a collection of objects, along with some ordering constraints, such as "A must be
before B," find an order of the objects such that all the ordering constraints hold.
CHAPTER 10
GREEDY ALGORITHMS
120
Algorithm: Create a directed graph over the objects, where there is an arc from A to B if
"A must be before B." Make a pass through the objects in arbitrary order. Each time you
find an object with in-degree of 0, greedily place it on the end of the current ordering,
delete all of its out-arcs, and recurse on its (former) children, performing the same check.
If this algorithm gets through all the objects without putting every object in the ordering,
there is no ordering which satisfies the constraints.
TEST YOUR GREEDY KNOWLEDGE
Solve UVa problems related which utilizes Greedy algorithms:
10020 - Minimal Coverage
10340 - All in All
10440 - Ferry Loading (II)
CHAPTER 11
DYNAMIC PROGRAMMING
121
CHAPTER 11
DYNAMIC PROGRAMMING
else
return Non_DP(n-1) + Non_DP(n-2);
}
// top down DP
int DP_Top_Down(int n) {
// base case
if (n == 1 || n == 2)
return 1;
// immediately return the previously computed result
if (memo[n] != 0)
return memo[n];
// otherwise, do the same as Non_DP
memo[n] = DP_Top_Down(n-1) + DP_Top_Down(n-2);
return memo[n];
}
// fastest DP, bottom up, store the previous results in array
int DP_Bottom_Up(int n) {
memo[1] = memo[2] = 1; // default values for DP algorithm
// from 3 to n (we already know that fib(1) and fib(2) = 1
for (int i=3; i<=n; i++)
memo[i] = memo[i-1] + memo[i-2];
return memo[n];
}
void main() {
int z;
// this will be the slowest
for (z=1; z<MAX; z++) printf("%d-",Non_DP(z));
printf("\n\n");
// this will be much faster than the first
for (z=0; z<MAX; z++) memo[z] = 0;
for (z=1; z<MAX; z++) printf("%d-",DP_Top_Down(z));
printf("\n\n");
/* this normally will be the fastest */
for (z=0; z<MAX; z++) memo[z] = 0;
for (z=1; z<MAX; z++) printf("%d-",DP_Bottom_Up(z));
printf("\n\n");
}
122
CHAPTER 11
DYNAMIC PROGRAMMING
123
CHAPTER 11
DYNAMIC PROGRAMMING
124
Let
Ai..j
(i
<
j)
denote
the
result
of
multiplying
AiAi+1..Aj.
Ai..j can be obtained by splitting it into Ai..k and Ak+1..j and then multiplying the subproducts. There are j-i possible splits (i.e. k=i,...,j-1)
Within the optimal parenthesization of Ai..j :
(a) the parenthesization of Ai..k must be optimal
(b) the parenthesization of Ak+1..j must be optimal
Because if they are not optimal, then there exist other split which is better, and we should
choose that split and not this split.
Step 2: Recursive formulation
m[i,j] = 0, if i=j
= min i<=k<j { m[i,k]+m[k+1,j]+pi-1pkpj }, if i<j
let s[i,j] be the value k where the optimal split occurs.
Step 3 Computing the Optimal Costs
Matric-Chain-Order(p)
n = length[p]-1
CHAPTER 11
DYNAMIC PROGRAMMING
125
for i = 1 to n do
m[i,i] = 0
for l = 2 to n do
for i = 1 to n-l+1 do
j = i+l-1
m[i,j] = infinity
for k = i to j-1 do
q = m[i,k] + m[k+1,j] + pi-1*pk*pj
if q < m[i,j] then
m[i,j] = q
s[i,j] = k
return m and s
Note: As any other DP solution, MCM also can be solved using Top
Down recursive algorithm using memoization. Sometimes, if you cannot
visualize the Bottom Up, approach, just modify your original Top Down
recursive solution by including memoization. You'll save a lot of time by
avoiding repetitive calculation of sub-problems.
CHAPTER 11
DYNAMIC PROGRAMMING
126
m=strlen(X);
n=strlen(Y);
for (i=1;i<=m;i++) c[i][0]=0;
for (j=0;j<=n;j++) c[0][j]=0;
for (i=1;i<=m;i++)
for (j=1;j<=n;j++) {
if (X[i-1]==Y[j-1]) {
c[i][j]=c[i-1][j-1]+1;
b[i][j]=1; /* from north west */
}
else if (c[i-1][j]>=c[i][j-1]) {
c[i][j]=c[i-1][j];
b[i][j]=2; /* from north */
}
else {
c[i][j]=c[i][j-1];
b[i][j]=3; /* from west */
}
}
return c[m][n];
}
CHAPTER 11
DYNAMIC PROGRAMMING
127
Edit Distance
Input: Given two string, Cost for deletion, insertion, and replace
Output: Give the minimum actions needed to transform first string into the second one.
Edit Distance problem is a bit similar to LCS. DP Solution for this problem is very useful
in Computational Biology such as for comparing DNA.
Let d(string1,string2) be the distance between these 2 strings.
CHAPTER 11
DYNAMIC PROGRAMMING
128
A two-dimensional matrix, m[0..|s1|,0..|s2|] is used to hold the edit distance values, such
that m[i,j] = d(s1[1..i], s2[1..j]).
m[0][0] = 0;
for (i=1; i<length(s1); i++) m[i][0] = i;
for (j=1; j<length(s2); j++) m[0][j] = j;
for (i=0; i<length(s1); i++)
for (j=0; j<length(s2); j++) {
val = (s1[i] == s2[j]) ? 0 : 1;
m[i][j] = min( m[i-1][j-1] + val,
min(m[i-1][j]+1 , m[i][j-1]+1));
}
To output the trace, use another array to store our action along the way. Trace back these
values later.
TEST YOUR EDIT DISTANCE KNOWLEDGE
164 - String Computer
526 - String Distance and Edit Process
Example of LIS
CHAPTER 11
DYNAMIC PROGRAMMING
129
A
A
A
A
A
A
A
A
A
-i
-i
-i
-i
-i
-i
-i
-i
-i
2 3 4 5 6 7 8
-7,10, 9, 2, 3, 8, 8, 1
i, i,
-7, i,
-7,10,
-7, 9,
-7, 2,
-7, 2,
-7, 2,
-7, 2,
-7, 1,
i,
i,
i,
i,
i,
3,
3,
3,
3,
i,
i,
i,
i,
i,
i,
8,
8,
8,
i,
i,
i,
i,
i,
i,
i,
i,
i,
i,
i,
i,
i,
i,
i,
i,
i,
i,
i,
i,
i,
i,
i,
i,
i,
i,
i,
i
i
i
i
i
i
i
i
i
You can see that the length of LIS is 4, which is correct. To reconstruct the LIS, at each
step, store the predecessor array as in standard LIS + this time remember the actual
values, since array A only store the last element in the subsequence, not the actual values.
CHAPTER 11
DYNAMIC PROGRAMMING
130
Zero-One Knapsack
Input: N items, each with various Vi (Value) and Wi (Weight) and max Knapsack size
MW.
Output: Maximum value of items that one can carry, if he can either take or not-take a
particular item.
Let C[i][w] be the maximum value if the available items are {X1,X2,...,Xi} and the
knapsack size is w.
if Wi > w (this item too heavy for our knapsack),skip this item C[i][w] = C[i-1][w];
CHAPTER 11
DYNAMIC PROGRAMMING
131
Counting Change
#include <stdio.h>
#define MAXTOTAL 10000
long long nway[MAXTOTAL+1];
int coin[5] = { 50,25,10,5,1 };
void main()
{
int i,j,n,v,c;
scanf("%d",&n);
v = 5;
nway[0] = 1;
for (i=0; i<v; i++) {
c = coin[i];
for (j=c; j<=n; j++)
nway[j] += nway[j-c];
}
printf("%lld\n",nway[n]);
}
CHAPTER 11
DYNAMIC PROGRAMMING
132
CHAPTER 11
DYNAMIC PROGRAMMING
133
Problems that can be solved using Floyd Warshall and it's variant, which belong to the
category all-pairs shortest path algorithm, can be categorized as Dynamic Programming
solution. Explanation regarding Floyd Warshall can be found in Graph section.
Other than that, there are a lot of ad hoc problems that can utilize DP, just remember that
when the problem that you encountered exploits optimal sub-structure and repeating subproblems, apply DP techniques, it may be helpful.
TEST YOUR DP KNOWLEDGE
Solve UVa problems related with Ad-Hoc DP:
108 - Maximum Sum
836 - Largest Submatrix
10003 - Cutting Sticks
10465 - Homer Simpson
CHAPTER 12
GRAPHS
134
CHAPTER 12 GRAPHS
A graph is a collection of vertices V and a collection of edges E consisting of pairs of
vertices. Think of vertices as ``locations''. The set of vertices is the set of all the possible
locations. In this analogy, edges represent paths between pairs of those locations. The set
[2]
E contains all the paths between the locations.
Vertices and Edges
Given a set of computers and a set of wires running between pairs of computers,
what is the minimum number of machines whose crash causes two given machines
to be unable to communicate? (The two given machines will not crash.)
Graph: The vertices of the graph are the computers. The edges are the wires between the
computers. Graph problem: minimum dominating sub-graph.
CHAPTER 12
GRAPHS
135
Farmer John owns a large number of fences, which he must periodically check for
integrity. He keeps track of his fences by maintaining a list of points at which
fences intersect. He records the name of the point and the one or two fence names
that touch that point. Every fence has two end points, each at some intersection
point, although the intersection point may be the end point of only one fence.
Given a fence layout, calculate if there is a way for Farmer John to ride his horse to
all of his fences without riding along a fence more than once. Farmer John can start
and finish anywhere, but cannot cut across his fields (i.e., the only way he can
travel between intersection points is along a fence). If there is a way, find one way.
Graph: Farmer John starts at intersection points and travels between the points along
fences. Thus, the vertices of the underlying graph are the intersection points, and the
fences represent edges. Graph problem: Traveling Salesman Problem.
Knight moves
Graph: The graph here is harder to see. Each location on the chessboard represents a
vertex. There is an edge between two positions if it is a legal knight move. Graph
Problem: Single Source Shortest Path.
CHAPTER 12
GRAPHS
136
Overfencing
Farmer John created a huge maze of fences in a field. He omitted two fence
segments on the edges, thus creating two ``exits'' for the maze. The maze is a
``perfect'' maze; you can find a way out of the maze from any point inside it.
Given the layout of the maze, calculate the number of steps required to exit the
maze from the ``worst'' point in the maze (the point that is ``farther'' from either
exit when walking optimally to the closest exit).
Here's
what
one
particular
W=5,
H=3
maze
looks
like:
+-+-+-+-+-+
|
|
+-+ +-+ + +
| |||
+ +-+-+ + +
|| |
+-+ +-+-+-+
Graph: The vertices of the graph are positions in the grid. There is an edge between two
vertices if they represent adjacent positions that are not separated by a wall.
Terminology
An edge is a self-loop if it is of the form (u,u). The sample graph contains no self-loops.
A graph is simple if it neither contains self-loops nor contains an edge that is repeated in
E. A graph is called a multigraph if it contains a given edge more than once or contain
self-loops. For our discussions, graphs are assumed to be simple. The example graph is a
simple graph.
An edge (u,v) is incident to both vertex u and vertex v. For example, the edge (1,3) is
incident to vertex 3.
The degree of a vertex is the number of edges which are incident to it. For example,
vertex 3 has degree 3, while vertex 4 has degree 1.
CHAPTER 12
GRAPHS
137
Vertex u is adjacent to vertex v if there is some edge to which both are incident (that is,
there is an edge between them). For example, vertex 2 is adjacent to vertex 5.
A graph is said to be sparse if the total number of edges is small compared to the total
number possible ((N x (N-1))/2) and dense otherwise. For a given graph, whether it is
dense or sparse is not well-defined.
Directed Graph
CHAPTER 12
GRAPHS
138
e1
e2
e3
e4
e5
V1
4
1
2
6
3
V2
3
3
5
1
6
CHAPTER 12
GRAPHS
139
Adjacency Matrix
V1
V2
V3
V4
V5
V6
V1
0
0
1
0
0
1
V2
0
0
0
0
1
0
V3
1
0
0
1
0
1
V4
0
0
1
0
0
0
V5
0
1
0
0
0
0
V6
1
0
1
0
0
0
It is sometimes helpful to use the fact that the (i,j) entry of the adjacency matrix raised to
the k-th power gives the number of paths from vertex i to vertex j consisting of exactly k
edges.
Adjacency List
The third representation of a matrix is to keep track of all the edges incident to a given
vertex. This can be done by using an array of length N, where N is the number of
vertices. The i-th entry in this array is a list of the edges incident to i-th vertex (edges are
represented by the index of the other vertex incident to that edge).
CHAPTER 12
GRAPHS
140
This representation is much more difficult to code, especially if the number of edges
incident to each vertex is not bounded, so the lists must be linked lists (or dynamically
allocated). Debugging this is difficult, as following linked lists is more difficult.
However, this representation uses about as much memory as the edge list. Finding the
vertices adjacent to each node is very cheap in this structure, but checking if two vertices
are adjacent requires checking all the edges adjacent to one of the vertices. Adding an
edge is easy, but deleting an edge is difficult, if the locations of the edge in the
appropriate lists are not known.
Extend this representation to handle weighted graphs by maintaining both the weight and
the other incident vertex for each edge instead of just the other incident vertex.
Multigraphs are already representable. Directed graphs are also easily handled by this
representation, in one of several ways: store only the edges in one direction, keep a
separate list of incoming and outgoing arcs, or denote the direction of each arc in the list.
Example
The adjacency list representation of the example undirected graph is as follows:
Vertex
1
2
3
4
5
6
Adjacent Vertices
3, 6
5
6, 4, 1
3
2
3, 1
Implicit Representation
For some graphs, the graph itself does not have to be stored at all. For example, for the
Knight moves and Overfencing problems, it is easy to calculate the neighbors of a vertex,
check adjacency, and determine all the edges without actually storing that information,
thus, there is no reason to actually store that information; the graph is implicit in the data
itself.
If it is possible to store the graph in this format, it is generally the correct thing to do, as it
saves a lot on storage and reduces the complexity of your code, making it easy to both
write and debug.
CHAPTER 12
GRAPHS
141
If N is the number of vertices, M the number of edges, and d max the maximum degree of
a node, the following table summarizes the differences between the representations:
Efficiency
Space
Adjacency Check
List of Adjacent Vertices
Add Edge
Delete Edge
Edge List
2*M
M
M
1
M
Adj Matrix
N^2
1
N
1
2
Adj List
2xM
d max
d max
1
2*d max
Connectedness
->
An undirected graph is said to be connected if there is a path from every vertex to every
other vertex. The example graph is not connected, as there is no path from vertex 2 to
vertex 4. However, if you add an edge between vertex 5 and vertex 6, then the graph
becomes connected.
A component of a graph is a maximal subset of the vertices such that every vertex is
reachable from each other vertex in the component. The original example graph has two
components: {1, 3, 4, 6} and {2, 5}. Note that {1, 3, 4} is not a component, as it is not
maximal.
A directed graph is said to be strongly connected if there is a path from every vertex to
every other vertex.
A strongly connected component of a directed graph is a vertex u and the collection of all
vertices v such that there is a path from u to v and a path from v to u.
CHAPTER 12
GRAPHS
142
Subgraphs
A rooted tree
Many trees are what is called rooted, where there is a notion of the "top" node, which is
called the root. Thus, each node has one parent, which is the adjacent node which is
closer to the root, and may have any number of children, which are the rest of the nodes
adjacent to it. The tree above was drawn as a rooted tree.
Forest
CHAPTER 12
GRAPHS
143
Complete Graph
Bipartite Graph
Uninformed Search
CHAPTER 12
GRAPHS
144
state space. A path through the state space from the initial state to a goal state is a
solution.
In real life most problems are ill-defined, but with some analysis, many problems can fit
into the state space model. A single general search algorithm can be used to solve any
problem; specific variants of the algorithm embody different strategies. Search
algorithms are judged on the basis of completeness, optimality, time complexity, and
space complexity. Complexity depends on b, the branching factor in the state space,
and d, the depth of the shallowest solution.
This 6 search type below (there are more, but we only show 6 here) classified as
uninformed search, this means that the search have no information about the number of
steps or the path cost from the current state to the goal - all they can do is distinguish a
goal state from a non-goal state. Uninformed search is also sometimes called blind
search.
Breadth First Serach (BFS)
Breadth-first search expands the shallowest node in the search tree first. It is complete,
optimal for unit-cost operators, and has time and space complexity of O(b^d). The space
complexity makes it impractical in most cases.
Using BFS strategy, the root node is expanded first, then all the nodes generated by the
root node are expanded next, and their successors, and so on. In general, all the nodes at
depth d in the search tree are expanded before the nodes at depth d+1.
Algorithmically:
BFS(G,s) {
initialize vertices;
Q = {s];
while (Q not empty) {
u = Dequeue(Q);
for each v adjacent to u do {
if (color[v] == WHITE) {
color[v] = GRAY;
d[v] = d[u]+1; // compute d[]
p[v] = u; // build BFS tree
Enqueue(Q,v);
}
}
color[u] = BLACK;
}
CHAPTER 12
GRAPHS
145
Note: BFS can compute d[v] = shortest-path distance from s to v, in terms of minimum
number of edges from s to v (un-weighted graph). Its breadth-first tree can be used to
represent the shortest-path.
BFS Solution to Popular JAR Problem
#include<stdio.h>
#include<conio.h>
#include<values.h>
#define N 105
#define MAX MAXINT
int act[N][N], Q[N*20][3], cost[N][N];
int a, p, b, m, n, fin, na, nb, front, rear;
void init()
{
front = -1, rear = -1;
for(int i=0; i<N; i++)
for(int j=0; j<N; j++)
cost[i][j] = MAX;
cost[0][0] = 0;
}
void nQ(int r, int c, int p)
{
Q[++rear][0] = r, Q[rear][1] = c, Q[rear][2] = p;
}
void dQ(int *r, int *c, int *p)
{
*r = Q[++front][0], *c = Q[front][1], *p = front;
}
void op(int i)
{
int currCapA, currCapB;
if(i==0)
na = 0, nb = b;
else if(i==1)
nb = 0, na = a;
else if(i==2)
na = m, nb = b;
else if(i==3)
nb = n, na = a;
else if(i==4)
{
if(!a && !b)
CHAPTER 12
GRAPHS
return;
currCapB = n - b;
if(currCapB <= 0)
return;
if(a >= currCapB)
nb = n, na = a, na -= currCapB;
else
nb = b, nb += a, na = 0;
}
else
{
}
void bfs()
{
nQ(0, 0, -1);
do{
dQ(&a, &b, &p);
if(a==fin)
break;
for(int i=0; i<6; i++)
{
op(i); /* na, nb will b changed for this func
according to values of a, b
*/
if(cost[na][nb]>cost[a][b]+1)
{
cost[na][nb]=cost[a][b]+1;
act[na][nb] = i;
nQ(na, nb, p);
}
}
} while (rear!=front);
}
void dfs(int p)
{
int i = act[na][nb];
if(p==-1)
return;
na = Q[p][0], nb = Q[p][1];
dfs(Q[p][2]);
if(i==0)
146
CHAPTER 12
GRAPHS
147
printf("Empty A\n");
else if(i==1)
printf("Empty B\n");
else if(i==2)
printf("Fill A\n");
else if(i==3)
printf("Fill B\n");
else if(i==4)
printf("Pour A to B\n");
else
printf("Pout B to A\n");
}
void main()
{
clrscr();
while(scanf("%d%d%d", &m, &n, &fin)!=EOF)
{
printf("\n");
init();
bfs();
dfs(Q[p][2]);
printf("\n");
}
}
Uniform-cost search expands the least-cost leaf node first. It is complete, and unlike
breadth-first search is optimal even when operators have differing costs. Its space and
time complexity are the same as for BFS.
BFS finds the shallowest goal state, but this may not always be the least-cost solution for
a general path cost function. UCS modifies BFS by always expanding the lowest-cost
node on the fringe.
Depth First Search (DFS)
Depth-first search expands the deepest node in the search tree first. It is neither
complete nor optimal, and has time complexity of O(b^m) and space complexity of
O(bm), where m is the maximum depth. In search trees of large or infinite depth, the time
complexity makes this impractical.
DFS always expands one of the nodes at the deepest level of the tree. Only when the
search hits a dead end (a non-goal node with no expansion) does the search go back and
expand nodes at shallower levels.
CHAPTER 12
GRAPHS
148
Algorithmically:
DFS(G) {
for each vertex u in V
color[u] = WHITE;
time = 0; // global variable
for each vertex u in V
if (color [u] == WHITE)
DFS_Visit(u);
}
DFS_Visit(u) {
color[u] = GRAY;
time = time + 1; // global variable
d[u] = time; // compute discovery time d[]
for each v adjacent to u
if (color[v] == WHITE) {
p[v] = u; // build DFS-tree
DFS_Visit(u);
}
color[u] = BLACK;
time = time + 1; // global variable
f[u] = time; // compute finishing time f[]
}
CHAPTER 12
GRAPHS
149
If the goal node has been found, announce success, otherwise announce failure.
Note: This implementation differs with BFS in insertion of first element's children, DFS
from FRONT while BFS from BACK. The worst case for DFS is the best case for BFS
and vice versa. However, avoid using DFS when the search trees are very large or with
infinite maximum depths.
N Queens Problem
The most obvious solution to code is to add queens recursively to the board one by one,
trying all possible queen placements. It is easy to exploit the fact that there must be
exactly one queen in each column: at each step in the recursion, just choose where in the
current column to put the queen.
DFS Solution
1 search(col)
2
if filled all columns
3
print solution and exit
4
for each row
5
if board(row, col) is not attacked
6
place queen at (row, col)
7
search(col+1)
8
remove queen at (row, col)
Calling search(0) begins the search. This runs quickly, since there are relatively few
choices at each step: once a few queens are on the board, the number of non-attacked
squares goes down dramatically.
This is an example of depth first search, because the algorithm iterates down to the
bottom of the search tree as quickly as possible: once k queens are placed on the board,
boards with even more queens are examined before examining other possible boards with
only k queens. This is okay but sometimes it is desirable to find the simplest solutions
before trying more complex ones.
Depth first search checks each node in a search tree for some property. The search tree
might look like this:
CHAPTER 12
GRAPHS
150
CHAPTER 12
GRAPHS
151
The space complexity of iterative deepening is just the space complexity of depth first
search: O(n). The time complexity, on the other hand, is more complex. Each truncated
depth first search stopped at depth k takes ck time. Then if d is the maximum number of
decisions, depth first iterative deepening takes c^0 + c^1 + c^2 + ... + c^d time.
Which to Use?
Once you've identified a problem as a search problem, it's important to choose the right
type of search. Here are some things to think about.
Search
Time
Space
DFS
O(c^k)
O(k)
BFS
O(c^d)
O(c^d)
DFS+ID
O(c^d)
O(d)
When to use
Must search tree anyway, know the level the
answers are on, or you aren't looking for the
shallowest number.
Know answers are very near top of tree, or
want shallowest answer.
Want to do BFS, don't have enough space,
and can spare the time.
Depth-limited search places a limit on how deep a depth-first search can go. If the limit
happens to be equal to the depth of shallowest goal state, then time and space complexity
are minimized.
DLS stops to go any further when the depth of search is longer than what we have
defined.
CHAPTER 12
GRAPHS
152
Iterative deepening search calls depth-limited search with increasing limits until a goal
is found. It is complete and optimal, and has time complexity of O(b^d)
IDS is a strategy that sidesteps the issue of choosing the best depth limit by trying all
possible depth limits: first depth 0, then depth 1, then depth 2, and so on. In effect, IDS
combines the benefits of DFS and BFS.
Bidirectional Search
Bidirectional search can enormously reduce time complexity, but is not always
applicable. Its memory requirements may be impractical.
BDS simultaneously search both forward form the initial state and backward from the
goal, and stop when the two searches meet in the middle, however search like this is not
always possible.
Superprime Rib
A square township has been partitioned into n 2 square plots. The Farm is located in
the upper left plot and the Market is located in the lower left plot. Betsy takes a tour
of the township going from Farm to Market by walking through every plot exactly
once. Write a program that will count how many unique tours Betsy can take in
going from Farm to Market for any value of n <= 6.
CHAPTER 12
GRAPHS
153
Since the number of solutions is required, the entire tree must be searched, even if one
solution is found quickly. So it doesn't matter from a time perspective whether DFS or
BFS is used. Since DFS takes less space, it is the search of choice for this problem.
Udder Travel
The Udder Travel cow transport company is based at farm A and owns one cow
truck which it uses to pick up and deliver cows between seven farms A, B, C, D, E,
F, and G. The (commutative) distances between farms are given by an array. Every
morning, Udder Travel has to decide, given a set of cow moving orders, the order
in which to pick up and deliver cows to minimize the total distance traveled. Here
are the rules:
1. The truck always starts from the headquarters at farm A and must return
there when the day's deliveries are done.
2. The truck can only carry one cow at time.
3. The orders are given as pairs of letters denoting where a cow is to be picked
up followed by where the cow is to be delivered.
Your job is to write a program that, given any set of orders, determines the shortest
route that takes care of all the deliveries, while starting and ending at farm A.
Since all possibilities must be tried in order to ensure the best one is found, the entire tree
must be searched, which takes the same amount of time whether using DFS or BFS.
Since DFS uses much less space and is conceptually easier to implement, use that.
Desert Crossing
A group of desert nomads is working together to try to get one of their group
across the desert. Each nomad can carry a certain number of quarts of water, and
each nomad drinks a certain amount of water per day, but the nomads can carry
differing amounts of water, and require different amounts of water. Given the
carrying capacity and drinking requirements of each nomad, find the minimum
number of nomads required to get at least one nomad across the desert.
All the nomads must survive, so every nomad that starts out must either turn back
at some point, carrying enough water to get back to the start or must reach the
other side of the desert. However, if a nomad has surplus water when it is time to
turn back, the water can be given to their friends, if their friends can carry it.
CHAPTER 12
GRAPHS
154
This problem actually is two recursive problems: one recursing on the set of nomads to
use, the other on when the nomads turn back. Depth-first search with iterative deepening
works well here to determine the nomads required, trying first if any one can make it
across by themselves, then seeing if two work together to get across, etc.
Addition Chains
An addition chain is a sequence of integers such that the first number is 1, and
every subsequent number is the sum of some two (not necessarily unique) numbers
that appear in the list before it. For example, 1 2 3 5 is such a chain, as 2 is 1+1, 3
is 2+1, and 5 is 2+3. Find the minimum length chain that ends with a given
number.
Depth-first search with iterative deepening works well here, as DFS has a tendency to first
try 1 2 3 4 5 ... n, which is really bad and the queue grows too large very quickly for BFS.
Informed Search
Unlike Uninformed Search, Informed Search knows some information that can be used to
improve the path selection. Examples of Informed Search: Best First Search, Heuristic
Search such as A*.
Best First Search
we define a function f(n) = g(n) where g(n) is the estimated value from node 'n' to goal.
This search is "informed" because we do a calculation to estimate g(n)
A* Search
f(n) = h(n) + g(n), similar to Best First Search, it uses g(n), but also uses h(n), the total
cost incurred so far. The best search to consider if you know how to compute g(n).
CHAPTER 12
GRAPHS
155
Components
Flood fill can be performed three basic ways: depth-first, breadth-first, and breadth-first
scanning. The basic idea is to find some node which has not been assigned to a
component and to calculate the component which contains. The question is how to
calculate the component.
In the depth-first formulation, the algorithm looks at each step through all of the
neighbors of the current node, and, for those that have not been assigned to a component
yet, assigns them to this component and recurses on them.
In the breadth-first formulation, instead of recursing on the newly assigned nodes, they
are added to a queue.
In the breadth-first scanning formulation, every node has two values: component and
visited. When calculating the component, the algorithm goes through all of the nodes that
have been assigned to that component but not visited yet, and assigns their neighbors to
the current component.
CHAPTER 12
GRAPHS
156
The depth-first formulation is the easiest to code and debug, but can require a stack as big
as the original graph. For explicit graphs, this is not so bad, but for implicit graphs, such
as the problem presented has, the numbers of nodes can be very large.
The breadth-formulation does a little better, as the queue is much more efficient than the
run-time stack is, but can still run into the same problem. Both the depth-first and
breadth-first formulations run in N + M time, where N is the number of vertices and M is
the number of edges.
The breadth-first scanning formulation, however, requires very little extra space. In fact,
being a little tricky, it requires no extra space. However, it is slower, requiring up to N*N
+ M time, where N is the number of vertices in the graph.
Breadth-First Scanning
# component(i) denotes the component that node i is in
1 function flood_fill(new_component)
2 do
3
num_visited = 0
4
for all nodes i
5
if component(i) = -2
6
num_visited = num_visited + 1
7
component(i) = new_component
8
for all neighbors j of node i
9
if component(i) = nil
10
component(i) = -2
11 until num_visited = 0
12 function find_components
13
num_components = 0
14
for all nodes i
15
component(node i) = nil
16
for all nodes i
17
if component(node i) is nil
18
num_components = num_components + 1
19
component(i) = -2
20
flood_fill(component(num_components))
Running time of this algorithm is O(N 2), where N is the numbers of nodes. Every edge
is traversed twice (once for each end-point), and each node is only marked once.
CHAPTER 12
GRAPHS
157
Company Ownership
This can be solved via an adaptation of the calculating the vertices reachable from a
vertex in a directed graph. To calculate which vertices vertex A owns, keep track of the
``ownership percentage'' for each node. Initialize them all to zero. Now, at each recursive
step, mark the node as owned by vertex A and add the weight of all outgoing arcs to the
``ownership percentages.'' For all percentages that go above 50, recurse into those
vertices.
Street Race
The easiest algorithm is to remove each point in turn, and check to see if the end point is
reachable from the start point. This runs in O(N (M + N)) time. Since the original
problem stated that M <= 100, and N <= 50, this will run in time easily.
CHAPTER 12
GRAPHS
158
Cow Tours
Farmer John contracted out the building of a new barn. Unfortunately, the builder
mixed up the plans of Farmer John's barn with another set of plans. Farmer John's
plans called for a barn that only had one room, but the building he got might have
many rooms. Given a grid of the layout of the barn, tell Farmer John how many
rooms it has.
Analysis: The graph here is on the non-wall grid locations, with edge between adjacent
non-wall locations, although the graph should be stored as the grid, and not transformed
into some other form, as the grid is so compact and easy to work with.
Tree
CHAPTER 12
GRAPHS
159
node, which is called the root. Thus, each node has one parent, which is the adjacent
node which is closer to the root, and may have any number of children, which are the rest
of the nodes adjacent to it. The tree above was drawn as a rooted tree.
Minimum Spanning Trees
Spanning trees
A spanning tree of a graph is just a subgraph that contains all the vertices and is a tree. A
graph may have many spanning trees; for instance the complete graph on four vertices
o---o
|\ /|
|X|
|/ \|
o---o
has sixteen spanning trees:
o---o o---o o o o---o
| | |
| |
|
| | |
| |
|
| | |
| |
|
o o o---o o---o o---o
o---o
\/
X
/\
o o
o o o o o o
|\ /
\/
\ /|
|X
X
X|
|/ \
/\
/ \|
o o o---o o o
o o o---o o
|\ |
/ | /|
|\|
/ |/|
| \| /
|/ |
o o o---o o
o o---o
\
\
\
o o---o
o---o o o o o o---o
|\
| / \ |
/|
|\
|/
\|
/|
| \ |/
\| / |
o o o---o o---o o o
CHAPTER 12
GRAPHS
160
Now suppose the edges of the graph have weights or lengths. The weight of a tree is just
the sum of weights of its edges. Obviously, different trees have different lengths. The
problem: how to find the minimum length spanning tree?
Why minimum spanning trees?
The standard application is to a problem like phone network design. You have a business
with several offices; you want to lease phone lines to connect them up with each other;
and the phone company charges different amounts of money to connect different pairs of
cities. You want a set of lines that connects all your offices with a minimum total cost. It
should be a spanning tree, since if a network isn't a tree you can always remove some
edges and save money.
A less obvious application is that the minimum spanning tree can be used to
approximately solve the traveling salesman problem. A convenient formal way of
defining this problem is to find the shortest path that visits each point at least once.
Note that if you have a path visiting all points exactly once, it's a special kind of tree. For
instance in the example above, twelve of sixteen spanning trees are actually paths. If you
have a path visiting some vertices more than once, you can always drop some edges to
get a tree. So in general the MST weight is less than the TSP weight, because it's a
minimization over a strictly larger set.
On the other hand, if you draw a path tracing around the minimum spanning tree, you
trace each edge twice and visit all points, so the TSP weight is less than twice the MST
weight. Therefore this tour is within a factor of two of optimal.
How to find minimum spanning tree?
The stupid method is to list all spanning trees, and find minimum of list. We already
know how to find minima... But there are far too many trees for this to be efficient. It's
also not really an algorithm, because you'd still need to know how to list all the trees.
A better idea is to find some key property of the MST that lets us be sure that some edge
is part of it, and use this property to build up the MST one edge at a time.
CHAPTER 12
GRAPHS
161
For simplicity, we assume that there is a unique minimum spanning tree. You can get
ideas like this to work without this assumption but it becomes harder to state your
theorems or write your algorithms precisely.
Lemma: Let X be any subset of the vertices of G, and let edge e be the smallest edge
connecting X to G-X. Then e is part of the minimum spanning tree.
Proof: Suppose you have a tree T not containing e; then we want to show that T is not the
MST. Let e=(u,v), with u in X and v not in X. Then because T is a spanning tree it
contains a unique path from u to v, which together with e forms a cycle in G. This path
has to include another edge f connecting X to G-X. T+e-f is another spanning tree (it has
the same number of edges, and remains connected since you can replace any path
containing f by one going the other way around the cycle). It has smaller weight than t
since e has smaller weight than f. So T was not minimum, which is what we wanted to
prove.
Kruskal's algorithm
We'll start with Kruskal's algorithm, which is easiest to understand and probably the best
one for solving problems by hand.
Kruskal's algorithm:
sort the edges of G in increasing order by length
keep a subgraph S of G, initially empty
for each edge e in sorted order
if the endpoints of e are disconnected in S
add e to S
return S
Note that, whenever you add an edge (u,v), it's always the smallest connecting the part of
S reachable from u with the rest of G, so by the lemma it must be part of the MST.
This algorithm is known as a greedy algorithm, because it chooses at each step the
cheapest edge to add to S. You should be very careful when trying to use greedy
algorithms to solve other problems, since it usually doesn't work. E.g. if you want to find
a shortest path from a to b, it might be a bad idea to keep taking the shortest edges. The
greedy idea only works in Kruskal's algorithm because of the key property we proved.
Analysis: The line testing whether two endpoints are disconnected looks like it should be
slow (linear time per iteration, or O(mn) total). The slowest part turns out to be the
sorting step, which takes O(m log n) time.
CHAPTER 12
GRAPHS
162
Prim's algorithm
Rather than build a subgraph one edge at a time, Prim's algorithm builds a tree one vertex
at a time.
Prim's algorithm:
let T be a single vertex x
while (T has fewer than n vertices) {
find the smallest edge connecting T to G-T
add it to T
}
This only applicable to graph with unweighted edges, simply do BFS from start node to
end node, and stop the search when it encounters the first occurrence of end node.
The relaxation process updates the costs of all the vertices, v, connected to a vertex, u, if
we could improve the best estimate of the shortest path to v by including (u,v) in the path
to v. The relaxation procedure proceeds as follows:
CHAPTER 12
GRAPHS
163
initialize_single_source(Graph G,Node s)
for each vertex v in Vertices(G)
G.d[v]:=infinity
G.pi[v]:=nil
G.d[s]:=0;
This sets up the graph so that each node has no predecessor (pi[v] = nil) and the estimates
of the cost (distance) of each node from the source (d[v]) are infinite, except for the
source node itself (d[s] = 0).
Note that we have also introduced a further way to store a graph (or part of a graph - as
this structure can only store a spanning tree), the predecessor sub-graph - the list of
predecessors of each node, pi[j], 1 <= j <= |V|. The edges in the predecessor sub-graph
are (pi[v],v).
The relaxation procedure checks whether the current best estimate of the shortest distance
to v (d[v]) can be improved by going through u (i.e. by making u the predecessor of v):
relax(Node u,Node v,double w[][])
if d[v] > d[u] + w[u,v] then
d[v]:=d[u] + w[u,v]
pi[v]:=u
Dijkstra Algorithm
Dijkstra's algorithm (invented by Edsger W. Dijkstra) solves the problem of finding the
shortest path from a point in a graph (the source) to a destination. It turns out that one can
find the shortest paths from a given source to all points in a graph in the same time, hence
this problem is called the Single-source shortest paths problem.
There will also be no cycles as a cycle would define more than one path from the selected
vertex to at least one other vertex. For a graph, G=(V,E) where V is a set of vertices and
E is a set of edges.
Dijkstra's algorithm keeps two sets of vertices: S (the set of vertices whose shortest paths
from the source have already been determined) and V-S (the remaining vertices). The
other data structures needed are: d (array of best estimates of shortest path to each vertex)
& pi (an array of predecessors for each vertex)
The basic mode of operation is:
1. Initialise d and pi,
2. Set S to empty,
CHAPTER 12
GRAPHS
164
DIJKSTRA(Graph G,Node s)
initialize_single_source(G,s)
S:={ 0 }
/* Make S empty */
Q:=Vertices(G) /* Put the vertices in a PQ */
while not Empty(Q)
u:=ExtractMin(Q);
AddNode(S,u); /* Add u to S */
for each vertex v which is Adjacent with u
relax(u,v,w)
Bellman-Ford Algorithm
A more generalized single-source shortest paths algorithm which can find the shortest
path in a graph with negative weighted edges. If there is no negative cycle in the graph,
this algorithm will updates each d[v] with the shortest path from s to v, fill up the
predecessor list "pi", and return TRUE. However, if there is a negative cycle in the given
graph, this algorithm will return FALSE.
BELLMAN_FORD(Graph G,double w[][],Node s)
initialize_single_source(G,s)
for i=1 to |V[G]|-1
for each edge (u,v) in E[G]
relax(u,v,w)
for each edge (u,v) in E[G]
if d[v] > d[u] + w(u, v) then
return FALSE
return TRUE
CHAPTER 12
GRAPHS
165
There exist a more efficient algorithm for solving Single-source shortest path problem for
a Directed Acyclic Graph (DAG). So if you know for sure that your graph is a DAG, you
may want to consider this algorithm instead of using Djikstra.
DAG_SHORTEST_PATHS(Graph G,double w[][],Node s)
topologically sort the vertices of G // O(V+E)
initialize_single_source(G,s)
for each vertex u taken in topologically sorted order
for each vertex v which is Adjacent with u
relax(u,v,w)
Given a directed graph, the Floyd-Warshall All Pairs Shortest Paths algorithm computes
the shortest paths between each pair of nodes in O(n^3). In this page, we list down the
Floyd Warshall and its variant plus the source codes.
Given:
w : edge weights
d : distance matrix
p : predecessor matrix
w[i][j] = length of direct edge between i and j
d[i][j] = length of shortest path between i and j
p[i][j] = on a shortest path from i to j, p[i][j] is the last node before j.
Initialization
for (i=0; i<n; i++)
for (j=0; j<n; j++) {
d[i][j] = w[i][j];
p[i][j] = i;
}
for (i=0; i<n; i++) d[i][i] = 0;
CHAPTER 12
GRAPHS
166
The Algorithm
for (k=0;k<n;k++) /* k -> is the intermediate point */
for (i=0;i<n;i++) /* start from i */
for (j=0;j<n;j++) /* reaching j */
/* if i-->k + k-->j is smaller than the original i-->j */
if (d[i][k] + d[k][j] < d[i][j]) {
/* then reduce i-->j distance to the smaller one i->k->j */
graph[i][j] = graph[i][k]+graph[k][j];
/* and update the predecessor matrix */
p[i][j] = p[k][j];
}
In the k-th iteration of the outer loop, we try to improve the currently known shortest
paths by considering k as an intermediate node. Therefore, after the k-th iteration we
know those shortest paths that only contain intermediate nodes from the set {0, 1, 2,...,k}.
After all n iterations we know the real shortest paths.
Constructing a Shortest Path
print_path (int i, int j) {
if (i!=j)
print_path(i,p[i][j]);
print(j);
}
Transitive Hull
Given a directed graph, the Floyd-Warshall algorithm can compute the Transitive Hull in
O(n^3). Transitive means, if i can reach k and k can reach j then i can reach j. Transitive
Hull means, for all vertices, compute its reachability.
w : adjacency matrix
d : transitive hull
CHAPTER 12
GRAPHS
167
The Algorithm
for (k=0; k<n; k++)
for (i=0; i<n; i++)
for (j=0; j<n; j++)
/* d[i][j] is true if d[i][j] already true
or if we can use k as intermediate vertex to reach j from i,
otherwise, d[i][j] is false */
d[i][j] = d[i][j] || (d[i][k] && d[k][j]);
MiniMax Distance
Given a directed graph with edge lengths, the Floyd-Warshall algorithm can compute the
minimax distance between each pair of nodes in O(n^3). For example of a minimax
problem, refer to the Valladolid OJ problem below.
w : edge weights
d : minimax distance matrix
p : predecessor matrix
w[i][j] = length of direct edge between i and j
d[i][j] = length of minimax path between i and j
CHAPTER 12
GRAPHS
168
Initialization
for (i=0; i<n; i++)
for (j=0; j<n; j++)
d[i][j] = w[i][j];
for (i=0; i<n; i++)
d[i][i] = 0;
The Algorithm
for (k=0; k<n; k++)
for (i=0; i<n; i++)
for (j=0; j<n; j++)
d[i][j] = min(d[i][j], max(d[i][k], d[k][j]));
MaxiMin Distance
You can also compute the maximin distance with the Floyd-Warshall algorithm.
Maximin is the reverse of minimax. Again, look at Valladolid OJ problem given below to
understand maximin.
w : edge weights
d : maximin distance matrix
p : predecessor matrix
w[i][j] = length of direct edge between i and j
d[i][j] = length of maximin path between i and j
CHAPTER 12
GRAPHS
Initialization
for (i=0; i<n; i++)
for (j=0; j<n; j++)
d[i][j] = w[i][j];
for (i=0; i<n; i++)
d[i][i] = 0;
The Algorithm
for (k=0; k<n; k++)
for (i=0; i<n; i++)
for (j=0; j<n; j++)
d[i][j] = max(d[i][j], min(d[i][k], d[k][j]));
Safest Path
Given a directed graph where the edges are labeled with survival probabilities, you can
compute the safest path between two nodes (i.e. the path that maximizes the product of
probabilities along the path) with Floyd Warshall.
w : edge weights
p : probability matrix
w[i][j] = survival probability of edge between i and j
p[i][j] = survival probability of safest path between i and j
Initialization
for (i=0; i<n; i++)
for (j=0; j<n; j++)
p[i][j] = w[i][j];
for (i=0; i<n; i++)
p[i][i] = 1;
169
CHAPTER 12
GRAPHS
The Algorithm
for (k=0; k<n; k++)
for (i=0; i<n; i++)
for (j=0; j<n; j++)
p[i][j] = max(p[i][j], p[i][k] * p[k][j]);
Graph Transpose
Euler Cycle
Input: Connected, directed graph G = (V,E)
Output: A cycle that traverses every edge of G exactly once, although it may visit a
vertex more than once.
Theorem: A directed graph possesses an Eulerian cycle iff
1) It is connected
2) For all {v} in {V} indegree(v) = outdegree(v)
Euler Path
Input: Connected, directed graph G = (V,E)
Output: A path from v1 to v2, that traverses every edge of G exactly once, although it
may visit a vertex more than once.
170
CHAPTER 12
GRAPHS
171
CHAPTER 13
COMPUTER GEOMETRY
172
CHAPTER 13
COMPUTER GEOMETRY
173
Convex Hull
Basically, Convex Hull is the most basic and most popular computational geometry
problem. Many algorithms are available to solve this efficiently, with the best lower
bound O(n log n). This lower bound is already proven.
Convex Hull problem (2-D version):
Input: A set of points in Euclidian plane
Output: Find the minimum set of points that enclosed all other points.
Convex Hull algorithms:
a. Jarvis March / Gift Wrapping
b. Graham Scan
c. Quick Hull
d. Divide and Conquer
CHAPTER 14
174
Math
113,202 ,256,275,276,294326,332,347, 350,356,374,377,382,386,
412,465,471,474,485,498550,557,568,594,725,727,846,10006,10014,10019,10042,10060,10071,1009
3,10104,10106,10107,10110,10125,10127,10162,10190,10193,10195,10469
406,516,543,583,686,10140,10200,10490
190, 191, 378,438,476,477,478,10112,10221,10242,10245,10301,10432,10451
324,424,495,623,713,748,10013,10035,10106,10220, 10334
343,355,389,446,575,10183,10551
369,530
106,264,486,580
160, 324, 10323, 10338
495,10183,10334,10450
138,10408
10176,10551
Dynamic Programming
108, 116,136,348,495,507,585,640,836,10003,10036,10074,10130,10404
111,231,497,10051,10131
531, 10066, 10100, 10192,10405
147, 357, 674
164,526
Graph
1043, ,436,534,544,567,10048,10099,10171,112,117,122,193, 336,352,383, 429,469, 532, 536, 590,
614, 615, 657, 677, 679, 762,785,10000,10004,10009,10010,10116,10543
820, 10092, 10249
670,753,10080
352,572
315,796
10034,10147,10397
459,793,10507
167,278,439,750
Mixed Problems
153,156,195,454,630
120,10152,10194,10258
458,554,740,10008,10062
10020,10249,10340
162,462,555
464,533
130,133,144, 151, 305, 327,339,362,379402,440,556,637,758,10033,10500
312,320, 330, 337, 381,391,392400,403,445,488,706,10082
CHAPTER 14
Ad Hoc
Array
Manipulation
Binary Search
Backtracking
3n+1 Problem
175
This problems are available at (http://acm.uva.es/p). New problems are added after each online contest
at Valladolid Online Judge as well as after each ACM Regional Programming Contest, problems are
added to live ACM archive (http://cii-judge.baylor.edu/).
APPENDIX A
176
APPENDIX A
ACM PROGRAMMING PROBLEMS
This part of this book contains some interesting problems from
ACM/ICPC. Problems are collected from Valladolid Online Judge. You
can see the reference section for finding more problem sources.
APPENDIX A
177
APPENDIX A
178
Sample Input
20 5
100 10
200 15
Sample Output
5
14
23
Problem Setter : Ahmed Shamsul Arefin
APPENDIX A
179
The Output
For each test case, print one line containing the required number. This number will
always fit into an integer, i.e. it will be less than 2^31-1.
Sample Input
5
60
100
Sample Output
3
288
648
Problem Setter : Ahmed Shamsul Arefin
Satellites
The Problem
The radius of earth is 6440 Kilometer. There are many Satellites and Asteroids moving
around the earth. If two Satellites create an angle with the center of earth, can you find
out the distance between them? By distance we mean both the arc and chord distances.
Both satellites are on the same orbit. (However, please consider that they are revolving on
a circular path rather than an elliptical path.)
APPENDIX A
180
The Input
The input file will contain one or more test cases.
Each test case consists of one line containing two-integer s and a and a string "min" or
"deg". Here s is the distance of the satellite from the surface of the earth and a is the
angle that the satellites make with the center of earth. It may be in minutes ( ) or in
degrees ( 0 ). Remember that the same line will never contain minute and degree at a time.
The Output
For each test case, print one line containing the required distances i.e. both arc distance
and chord distance respectively between two satellites in Kilometer. The distance will be
a floating-point value with six digits after decimal point.
Sample Input
500 30 deg
700 60 min
200 45 deg
Sample Output
3633.775503 3592.408346
124.616509 124.614927
5215.043805 5082.035982
Problem Setter : Ahmed Shamsul Arefin
APPENDIX A
181
professors speech. After his invention, everyone got comfort again and that old teacher
started his everyday works as before.
So, if you ever visit BUET and see a teacher talking with a microphone, which is
connected to a IBM computer equipped with a voice recognition software and students
are taking their lecture from the computer screen, dont get thundered! Because now your
job is to write the same program which can decode that mad teacher's speech!
The Input
The input file will contain only one test case i.e. the encoded message.
The test case consists of one or more words.
The Output
For the given test case, print a line containing the decoded words. However, it is not so
hard task to replace each letter or punctuation symbol by the two immediately to its left
alphabet on your standard keyboard.
Sample Input
k[r dyt I[o
Sample Output
how are you
Problem Setter: Ahmed Shamsul Arefin
APPENDIX A
182
The Input
The input file will contain one or more test cases. Each test case consists of an integer n
(n<=4,294,967,295). Here n is the maximum number of trees.
The Output
For each test case, print one line containing the actual number of nodes.
Sample Input
5
14
42
Sample Output
3
4
5
Problem Setter: Ahmed Shamsul Arefin
Power of Cryptography
Background
Current work in cryptography involves (among other things) large prime numbers and
computing powers of numbers modulo functions of these primes. Work in this area has
resulted in the practical use of results from number theory and other branches of
mathematics once considered to be of only theoretical interest.
This problem involves the efficient computation of integer roots of numbers.
The Problem
Given an integer
and an integer
, the positive
root of p. In this problem, given such integers n and p, p will always
be of the form for an integer k (this integer is what your program must find).
APPENDIX A
183
The Input
The input consists of a sequence of integer pairs n and p with each integer on a line by
,
The Output
For each integer pair n and p the value
.
Sample Input
2
16
3
27
7
4357186184021382204544
Sample Output
4
3
1234
Roman Roulette
The historian Flavius Josephus relates how, in the Romano-Jewish conflict of 67 A.D., the
Romans took the town of Jotapata which he was commanding. Escaping, Jospehus found
himself trapped in a cave with 40 companions. The Romans discovered his whereabouts and
invited him to surrender, but his companions refused to allow him to do so. He therefore
suggested that they kill each other, one by one, the order to be decided by lot. Tradition has it
that the means for effecting the lot was to stand in a circle, and, beginning at some point,
count round, every third person being killed in turn. The sole survivor of this process was
Josephus, who then surrendered to the Romans. Which begs the question: had Josephus
previously practised quietly with 41 stones in a dark corner, or had he calculated
mathematically that he should adopt the 31st position in order to survive?
APPENDIX A
184
Having read an account of this gruesome event you become obsessed with the fear that you
will find yourself in a similar situation at some time in the future. In order to prepare yourself
for such an eventuality you decide to write a program to run on your hand-held PC which will
determine the position that the counting process should start in order to ensure that you will
be the sole survivor.
In particular, your program should be able to handle the following variation of the processes
described by Josephus. n > 0 people are initially arranged in a circle, facing inwards, and
numbered from 1 to n. The numbering from 1 to n proceeds consecutively in a clockwise
direction. Your allocated number is 1. Starting with person number i, counting starts in a
clockwise direction, until we get to person number k (k > 0), who is promptly killed. We then
proceed to count a further k people in a clockwise direction, starting with the person
immediately to the left of the victim. The person number k so selected has the job of burying
the victim, and then returning to the position in the circle that the victim had previously
occupied. Counting then proceeeds from the person to his immediate left, with the kth person
being killed, and so on, until only one person remains.
For example, when n = 5, and k = 2, and i = 1, the order of execution is 2, 5, 3, and 1. The
survivor is 4.
Input and Output
Your program must read input lines containing values for n and k (in that order), and for each
input line output the number of the person with which the counting should begin in order to
ensure that you are the sole survivor. For example, in the above case the safe starting position
is 3. Input will be terminated by a line containing values of 0 for n and k.
Your program may assume a maximum of 100 people taking part in this event.
Sample Input
1 1
1 5
0 0
Sample Output
1
1
APPENDIX A
185
Joseph's Cousin
The Problem
The Josephs problem is notoriously known. For those who are not familiar with the
problem, among n people numbered 1,2n, standing in circle every mth is going to be
executed and only the life of the last remaining person will be saved. Joseph was smart
enough to choose the position of the last remaining person, thus saving his life to give the
message about the incident.
Although many good programmers have been saved since Joseph spread out this
information, Josephs Cousin introduced a new variant of the malignant game. This
insane character is known for its barbarian ideas and wishes to clean up the world from
silly programmers. We had to infiltrate some the agents of the ACM in order to know the
process in this new mortal game. In order to save yourself from this evil practice, you
must develop a tool capable of predicting which person will be saved.
The Destructive Process
The persons are eliminated in a very peculiar order; m is a dynamical variable, which
each time takes a different value corresponding to the prime numbers succession
(2,3,5,7). So in order to kill the ith person, Josephs cousin counts up to the ith prime.
The Input
It consists of separate lines containing n [1..3501], and finishes with a 0.
The Output
The output will consist in separate lines containing the position of the person which life
will be saved.
Sample Input
6
0
Sample Output
4
APPENDIX A
186
Integer Inquiry
One of the first users of BIT's new supercomputer was Chip Diller. He extended his
exploration of powers of 3 to go from 0 to 333 and he explored taking various sums of those
numbers.
``This supercomputer is great,'' remarked Chip. ``I only wish Timothy were here to see these
results.'' (Chip moved to a new apartment, once one became available on the third floor of the
Lemon Sky apartments on Third Street.)
Input
The input will consist of at most 100 lines of text, each of which contains a single
VeryLongInteger. Each VeryLongInteger will be 100 or fewer characters in length, and will
only contain digits (no VeryLongInteger will be negative).
The final input line will contain a single zero on a line by itself.
Output
Your program should output the sum of the VeryLongIntegers given in the input.
Sample Input
123456789012345678901234567890
123456789012345678901234567890
123456789012345678901234567890
0
Sample Output
370370367037037036703703703670
APPENDIX A
187
The Decoder
Write a complete program that will correctly decode a set of characters into a valid message.
Your program should read a given file of a simple coded set of characters and print the exact
message that the characters contain. The code key for this simple coding is a one for one
character substitution based upon a single arithmetic manipulation of the printable portion of
the ASCII character set.
Your program should accept all sets of characters that use the same encoding scheme and
should print the actual message of each set of characters.
Sample Input
1JKJ'pz'{ol'{yhklthyr'vm'{ol'Jvu{yvs'Kh{h'Jvywvyh{pvu5
1PIT'pz'h'{yhklthyr'vm'{ol'Pu{lyuh{pvuhs'I|zpulzz'Thjopul'Jvywvyh{pvu5
1KLJ'pz'{ol'{yhklthyr'vm'{ol'Kpnp{hs'Lx|pwtlu{'Jvywvyh{pvu5
Sample Output
*CDC is the trademark of the Control Data Corporation.
*IBM is a trademark of the International Business Machine Corporation.
*DEC is the trademark of the Digital Equipment Corporation.
APPENDIX B
188
APPENDIX B
COMMON CODES/ROUTINES FOR PROGRAMMING
This
part
of
this
book
contains
some
COMMON
codes/routines/pseudocodes for programmers that one can EASILY use
during the contest hours.[10]
APPENDIX B
189
vector<int> primefactors(int a)
{
vector<int> primefactors;
for(int i=1;i<=a;++i)
if(a%i==0&&isprime(i))
{
primefactors.push_back(i);
a=a/i;i=1;
}
return primefactors;
}
int main()
{
int a=5,b=2500;
out<<"GCD = "<<gcd(a,b)<<endl;
out<<"LCM = "<<lcm(a,b)<<endl;
if(!isprime(b)) out<<"not
prime"<<endl;
vector <int> p =
primefactors(b);
for(int i=0;i<p.size();++i)
out<<p[i]<<endl;
return 0;
}
APPENDIX B
190
The another application of GCD is Extended Euclids Algorithm..We can solve the
formula d = ax + by => gcd(a,b) = ax + by. This algorithm take the
inputs a and b..and out put the d(gcd of a,b) and the value of the root x and y.
//******
Extended Euclids Algorithm
*****************//
#include<stdio.h>
unsigned long d,x,y;
void Extended_Euclid(unsigned long a, unsigned long b){
unsigned long x1;
if(b>a){
x1=a;
//if b>a so I used this if condition
a=b;
// result is ok but x and y swaped
b=x1;
}
if(b==0){
d=a;
x=1;
y=0;
return;
}
Extended_Euclid(b,a%b);
d = d;
x1 = x-(a/b) * y;
x = y;
y = x1;
}
int main(){
unsigned long a,b;
//
d = gcd(a,b) = ax+by
while(scanf("%lu %lu", &a, &b)==2){
Extended_Euclid(a,b);
printf("%lu %lu %lu\n",d,x,y);}return 0;}
APPENDIX B
191
GCD of N numbers:
This program takes a number that is for how many numbers you want to find the GCD
and show the GCD of them. This takes input until end of file.
//********
GCD for n numbers
#include<stdio.h>
int main(){
long gcd,a,b,n,i;
while(scanf("%ld",&n)==1){
scanf("%ld%ld",&a,&b);
i=2;
while(i<n){
gcd=g_c_d(a,b);
a=gcd;
******************//
i++;
scanf("%ld",&b);
}
gcd=g_c_d(a,b);
printf("%ld\n",gcd);
}
return 0;
}
It is also a important topic in programming. Suppose different clocks are set in 12 point,
and each and every clock has their own time to complete the cycle. When every clock
again set in the 12 point.? This type of problem can be solved by LCM. LCM was
implemented by the help of GCD.
LCM (m, n) = [m / GCD(m, n)] * n;
Or, D1=m / GCD(m, n);
D2=n / GCD(m, n);
LCM(m, n) = D1 * D2 * GCD(m, n);
APPENDIX B
192
return (a/GCD(a,b)*b);
}
int main(){
long a,b;
int n,i;
while(scanf("%d",&n)==1){
if(n==0) break;
scanf("%ld",&a);
for(i=1;i<n;i++){
scanf("%ld",&b);
a=LCM(a,b);
}
printf("%ld\n",a);
}
return 0;}
Factorials
//***
Factorial by recurtion
*************//
#include<stdio.h>
long fac(long x){
if(x==0)
return 1;
return x * fac(x-1);
}
/********************************************************************/
int main(){
long n,res;
while(scanf("%ld",& n)==1){
res=fac(n);
printf("%ld\n",res);
}
return 0;}
This is very easy, but one thing we have to know that factorials increases multiply. The
12th factorial is 479001600 which is very big so can you imagine the factorial of
1000!.? The above program can compute upto 12th factorials so for less then 12th we
can use it. But for time consideration in ACM we always try to avoids the recursion
process.
APPENDIX B
193
Iterative Factorial
//*********
Factorial by normal multiplication
#include<stdio.h>
long fac(long x){
long i,res=1;
for(i=1;i<=x;i++)
res*=i;
return res;
}
int main(){
long n,res;
while(scanf("%ld",&n)==1){
res=fac(n);
printf("%ld\n",res);
}
return 0;
}
*********//
So, how can we compute the factorial of big numbers? Here is a code that can show the
factorials up to 1000. And this a ACM problem (623-500!). This code is very efficient
too!. We pre-calculate all the 1000th factorials in a two dimensional array. In the main
function just takes input and then just print.
Factorial of Big Number!
#include<stdio.h>
#include<string.h>
char f[10000];
char factorial[1010][10000];
void multiply(int k){
int cin,sum,i;
int len = strlen(f);
cin=0;
i=0;
while(i<len){
sum=cin+(f[i] - '0') * k;
f[i] = (sum % 10) + '0';
i++;
cin = sum/10;
}
while(cin>0){
f[i++] = (cin%10) + '0';
cin/=10;
}
f[i]='\0';
for(int j=0;j<i;j++)
factorial[k][j]=f[j];
factorial[k][i]='\0';}
APPENDIX B
194
void fac(){
int k;
strcpy(f,"1");
for(k=2;k<=1000;k++)
multiply(k);
}
void print(int n){
int i;
int len = strlen(factorial[n]);
printf("%d!\n",n);
for(i=len-1;i>=0;i--){
printf("%c",factorial[n][i]);
}
printf("\n");
}
int main(){
int n;
factorial[0][0]='1';
factorial[1][0]='1';
fac();
while(scanf("%d",&n)==1){
print(n);
}
return 0;
}
Factorial Frequencies
Now how many digits in the factorial of N numbers..? Yes we can count them by the
above process. But we can do it simply!
//*********
How many digits in N factorials
*******************//
#include<stdio.h>
#include<math.h>
/*******************************************************************/
double count_digit(long a){
double sum;
long i;
if(a==0) return 1;
else{
sum=0;
for(i=1;i<=a;i++){
sum+=log10(i);
}
return floor(sum)+1;
}
}
/*******************************************************************/
int main(){
double sum;
long n;
APPENDIX B
195
while(scanf("%ld",&n)==1){
sum=count_digit(n);
printf("%.0lf\n",sum);
}
return 0;
}
We know that factorials of any number has so many zeros (0s) at lastexample 17! =
355687428096000. It has 3 last zero digits. So we now see how many trailing zeros have
in N factorials.
//***************
How many trailing zeros in N!
**********/*******//
#include<stdio.h>
long zero(long number,long factor){
long total,deno;
if(number==5) return 1;
total=0;
deno=factor;
while(deno<number){
total+=number/deno;
deno*=factor;
}
return total;
}
/*******************************************************************/
int main(){
long N,c2,c1;
while(scanf("%ld",&N)==1){
c1=zero(N,2);
c2=zero(N,5);
if(c1<c2) printf("%ld\n",c1);
else printf("%ld\n",c2);
}
return 0;
}
Big Mod
We are not always interested in the full answers, however. Sometimes the remainder
suffices for our purposes. In that case we use Modular Arithmetic. The key to efficient
modular arithmetic is understanding how the basic operation of addition, subtraction, and
multiplication work over a given modulus.
Addition:- (x + y)mod n..? = ((x mod n) + (y mod n)) mod n.
Subtraction:- (x-y) mod n....? = ((x mod n) - (y mod n)) mod n.
APPENDIX B
196
APPENDIX B
197
Following code help you to convert any integer number on any base from 2 to 36.
#include<string.h>
#include<stdio.h>
#define MAXDGT 200
/* *********************************************************
/*
A general swap function that swap two object.
/*
Input : Two object.
*/
/*
Return : None
*/
/* *********************************************************
template <class T>
void swap(T &x, T &y)
{
T tmp=x;
x=y;
y=tmp;
*/
*/
*/
};
/***************************************************************
/*
A general string reverse function that reverse the
/*
passed string and store the string int to the parameter.
/*
Input : A string
*/
/*
Return : None
/***************************************************************
void revstr(char *str)
{
int i=0,l=strlen(str);
while(i<l)
swap(str[i++],str[--l]);
}
*/
*/
*/
*/
*/
/******************************************************************* */
/*
A general base conversion function
*/
/*
Input : A number n and a base b
*/
/*
Return : A character array which contain the number n in base b */
/* ******************************************************************* */
char *itob(long int n,int b=10)
{
char num[MAXDGT];
int j,sign;
register int i=0;
APPENDIX B
do
num[i++]='-';
num[i]='\0';
revstr(num);
return num;
/* Sample main */
main(void)
{
printf(itob(71],36));
Decimal To Roman
Roman number is very useful number system. Often we need to convert a decimal
number into Roman number. In Roman number the following symbol are used.
i, v, x, l, c, m for 1, 5, 10, 50, 100 and 500 respectively.
#include<stdio.h>
/* **********************************
/*
Convert number 1 to 10
/*
Input : A integer number
/*
Return : None
/* **********************************
void unit(int n)
{
switch(n){
case 3 :
case 2 :
case 1 :
case 4 :
case 5 :
case 6 :
case 7 :
case 8 :
case 9 :
}
}
*/
*/
*/
*/
*/
printf("i");
printf("i");
printf("i"); break;
printf("i");
printf("v"); break;
printf("vi"); break;
printf("vii"); break;
printf("viii"); break;
printf("ix"); break;
/* **********************************
/*
Convert number 10 to 100
*/
*/
198
APPENDIX B
/*
Input : A integer number
/* **********************************
void ten(int n)
{
switch(n){
case 3 :
case 2 :
case 1 :
case 4 :
case 5 :
case 6 :
case 7 :
case 8 :
case 9 :
199
*/
*/
printf("x");
printf("x");
printf("x"); break;
printf("x");
printf("l"); break;
printf("lx"); break;
printf("lxx"); break;
printf("lxxx"); break;
printf("xc"); break;
}
}
/* **********************************
/*
Convert number 100 to 500
/*
Input : A integer number
/* **********************************
void hnd(int n)
{
switch(n){
case 3 :
case 2 :
case 1 :
case 4 :
case 5 :
}
}
*/
*/
*/
*/
printf("c");
printf("c");
printf("c"); break;
printf("c");
printf("M"); break;
/* *************************************************
/*
Convert an integer number into roman system
/*
Input : A integer number
/* *************************************************
void roman(int n)
{
int a,i;
if(n>=500)
{
a=n/500 ;
for(i=1;i<=a;i++)
printf("M");
}
n=n%500;
hnd(n/100);
n=n%100;
ten(n/10);
unit(n%10);
} main(void)
{
roman(390);
return 0;
}
*/
*/
*/
*/
APPENDIX B
200
Josephus Problem
Flavius Josephus was a famous historian of the first century. Legend has it that Josephus
wouldn't have lived to become famous without his mathematical talents. During the
Jewish-Roman war, he was among a band of 41 Jewish rebels trapped in cave by the
Romans.Preferring suicide to capture, the rebels decided to form a circle and, proceeding
around it, to kill every third remaining person until no one was left. But Josephus, along
with an un-indicted co-conspirator, wanted none of this suicide nonsense; so he quickly
calculated where he and his friend stand in the vicious circle.
#include <stdio.h>
#define MAX 150
/** Implementatiom of circular queue
**/
int queue[MAX];
int e,f,r;
/** _f is front; _r is rear & _e is element number **/
/* ************************************************** */
/*
A general push algorithm act over queue
*/
/* ************************************************** */
void push(int i)
{
r++;
e++;
if(r>=MAX)
r=1;
queue[r] = i;
}
/* ************************************************** */
/*
A general pop algorithm act over queue
*/
/* ************************************************** */
int pop(void)
{
e--;
int i=queue[f];
f++;
if(f>=MAX)
f = 1;
return i;
}
APPENDIX B
*/
*/
*/
*/
*/
*/
201
APPENDIX B
Combinations
/* *********************************************** */
/*
Calculate nCm
*/
/*
Input : Two integer number n m
*/
/*
Return : The nCm
*/
/* *********************************************** */
double nCr(int n,int m)
{
int k;
register int i,j;
double c,d;
c=d=1;
k=(m>(n-m))?m:(n-m);
for(j=1,i=k+1;(i<=n);i++,j++)
{
c*=i;
d*=j;
if( !fmod(c,d) && (d!=1) )
{ c/=d;
d=1;
}
}
return c;
}
/* A sample main function */
main(void)
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
printf("%.0lf\n",nCr(n,m));
return 0;
}
202
APPENDIX B
203
where,
l1, is the repeation times of first repeated character.
l2, is for second repeated character
and, so on
but remember calculating both n! and l1!* l2! * l3!* .. *ln may occurs overflow. So I
use
APPENDIX B
204
APPENDIX B
205
main(void)
{
char word[MAX];
int n;
int j=0;
scanf("%d",&n);
for(;n>0;n--)
{
scanf("%s",word);
printf("Data set %d: %.0f",++j,test(word));
putchar('\n');
}
return 0;
}
APPENDIX B
PRINT_ LCS(b,X,i,j)
1.
2.
3.
4.
5.
6.
7.
if i = 0 or j = 0
then return
if b[i,j] = 1
then PRINT_LCS(b,X,i-1,j-1)
else if b[i,j] = 2
then PRINT_LCS(b,X,i-1,j)
else PRINT_LCS(b,X,i,j-1)
206
APPENDIX B
207
APPENDIX B
else
p_lcs(b,i,j-1);
}
/* ********************************************* */
/*
This function calculate the LCS length
*/
/*
Input : Tow Sequence and an bool I. If
*/
/*
I is FALSE(0) then the function
*/
/*
do not print the LCS and if
*/
/*
TRUE(1) then print using the
*/
/*
above p_lcs function
*/
/*
Output: None
*/
/* ********************************************* */
void LCS_LNT(int l1, int l2,bool I)
{
int c[MAX][MAX]={0},b[MAX][MAX]={0};
register int i,j;
for(i=1;i<l1;i++)
{ for(j=1;j<l2;j++)
{ if( !(strcmp(str1[i-1],str2[j-1])))
{ c[i][j] = c[i-1][j-1] + 1;
b[i][j] = 1;
}
else if(c[i-1][j] >= c[i][j-1])
{ c[i][j] = c[i-1][j];
b[i][j] = 2;
}
else
c[i][j] = c[i][j-1];
}
}
if(I)
{
lcswl = 0;
p_lcs(b,l1-1,l2-1);
j = c[l1-1][l2-1];
printf("%s",lcs[0]);
for(i = 1; i< j ;i++)
printf(" %s",lcs[i]);
putchar('\n');
}
}
/* Sample main function */
main(void)
{
char word[50];
int i=0,j=0,l1,l2,ln;
while(scanf("%s",word)!=EOF)
{
ln = strlen(word);
if(ln==1)
if(word[0] == '#')
{
if(i==0)
{
i = 1;
208
APPENDIX B
209
l1 =j;
j = 0;
continue;
}
else
{
l2 = j;
j = i = 0;
test(l1+1,l2+1,1);
continue;
}
}
if(i==0) strcpy(str1[j++],word);
else
strcpy(str2[j++],word);
}
return 0;
}
Background
If two matrix A and B whose dimension is (m,n) and (n,p) respectively then the
multiplication of A and B needs m*n*p scalar multiplication.
Suppose you are given a sequence of n matrix A1,A2,.....An. Matrix Ai has dimension (Pi1,Pi). Your task is to parenthesize the product A1,A2,.....An such a way that minimize the
number of scalar product.
As matrix multiplication is associative so all the parenthesizations yield the same
product.
MATRIX_CHAIN_ORDER(P)
The input is a sequrnce P = <P0,P1,P2,.....Pn> where length[P] = n+1. The procedure uses
an auxlary table m[1....n,1....n] for storing the m[i,j] costs and auxlary table s[1...n,1...n]
that records which index of k achive the optimal cost in computing m[i,j].
1. n <- length[P]-1
2. for i <- 1 to n
3.
do m[i,j] <- 0
4. for l <- 2 to n
5.
do for i <- 1 to n l + 1
6.
do j <- i + l 1
APPENDIX B
7.
m[i,j] <- INF
//
8.
for k <- i to j 1
9.
do q <- m[i,k]+m[k+1,j]+ Pi-1PkPj
10.
if q < m[i,j]
11.
then m[i,j] <- q
12.
s[i,j] <- k
13. return m,s
210
INF is infnity
PRINT(s,i,j)
The following recursive procedure prints an optimal parentathesization of (Ai,Ai+1,.....Aj)
given the s table computed by
MATRIX_CHAIN_ORDER and indices i and j. The initial call PRINT(s,1,n) prints
optimal parentathesization of (A1,A2,.....An).
1.
2.
3.
4.
5.
6.
if i == j
then print Ai
else print (
PRINT(s,i,s[i,j])
PRINT(s,s[i,j]+1,j)
print )
Code :
#include<stdio.h>
#define MAX 15
#define INF 4294967295
/* number of matrix */
/* a maximum number of multiplication */
int num;
/* *************************************************
/*
Print out the sequence
/*
Input : A two dimentional array(created
/*
by the matrix chan order function)
/*
with there starting point
/*
Return : None
/* *************************************************
void print(unsigned long s[][MAX],int i,int j)
{
if(i==j)
printf("A%d",num++);
else
{
printf("(");
print(s,i,s[i][j]);
printf(" x ");
print(s,s[i][j]+1,j);
printf(")");
}
}
*/
*/
*/
*/
*/
*/
*/
APPENDIX B
211
/* *********************************************** */
/*
Find out the order
*/
/*
Input : A sequence of dimention and the
*/
/*
number of matrix
*/
/*
Return : none
*/
/* *********************************************** */
void matrix_chan_order(int *p,int n)
{
unsigned long m[MAX][MAX] = {0};
unsigned long s[MAX][MAX] = {0};
unsigned int q;
int l,j,i,k;
for(l = 2; l <= n ;l++)
{
for(i = 1 ; i <= n - l +1 ; i++)
{
j = i + l -1;
m[i][j] = INF;
for(k=i ; k < j ; k++)
q = m[i][k] + m[k+1][j] + p[i-1]*p[k]*p[j];
if(q < m[i][j])
{
m[i][j] = q;
s[i][j] = k;
}
}
}
}
num =1;
print(s,1,n);
}
/* A sample main function */
main(void)
{
int n;
int p[MAX]={0};
int i;
while(scanf("%d",&n),n)
{
for(i=1;i<=n;i++)
scanf("%d %d",&p[i-1],&p[i]);
matrix_chan_order(p,n);
putchar('\n');
}
return 0;
}
APPENDIX B
212
APPENDIX B
213
APPENDIX B
}
for(now=l-1;now>0;now--){
if(result[now]!='0')
break;
}
result[now+1]='\0';
reverse(result,L);
strcpy(result,L);
//return 1;
return sign;
}
int main(){
char fir[MAX],sec[MAX],res[MAX];
while(scanf("%s%s",&fir,&sec)==2){
if(call_minus(fir,sec,res)==1)
printf("-");
int len = strlen(res);
for(int i=0;i<len;i++)
printf("%c",res[i]);
printf("\n");
}
return 0;
}
214
APPENDIX B
for(f=0;f<=t_len;f++)
temp[f]='0';
temp[f]='\0';
for(s=0;s<s_len;s++){
hold=0;
for(f=0;f<f_len;f++){
res=(F[f]-'0')*(S[s]-'0') + hold+(temp[f+s]-'0');
temp[f+s]=res%10+'0';
hold=res/10;
if(f+s>r) r=f+s;
}
while(hold!=0){
res=hold+temp[f+s]-'0';
hold=res/10;
temp[f+s]=res%10+'0';
if(r<f+s) r=f+s;
f++;
}
}
for(;r>0 && temp[r]=='0';r--);
temp[r+1]='\0';
reverse(temp,result);
}
/***************************************************************/
int main(){
char fir[MAX],sec[MAX],res[MAX];
while(scanf("%s%s",&fir,&sec)==2){
call_mult(fir,sec,res);
int len=strlen(res);
for(int i=0;i<len;i++) printf("%c",res[i]);
printf("\n");
}
return 0;
}
215
APPENDIX B
216
APPENDIX B
S[s]='\0';
for(now=0,hold=0;now<l;now++){
diff=L[now]-(S[now]+hold);
if(diff<0){
hold=1;
result[now]=10+diff+'0';
}
else{
result[now]=diff+'0';
hold=0;
}
}
for(now=l-1;now>0;now--){
if(result[now]!='0')
break;
}
result[now+1]='\0';
reverse(result,L);
strcpy(result,L);
return 1;
}
/****************************************************************/
void call_sqrt(char *number,char *result,char *extra){
int num,start,e,mul,l,r=0,len;
char left[MAX],after[MAX];
char who[5],temp[MAX],two[5];
len=strlen(number);
if(len%2==0){
num=10*(number[0]-'0') + number[1]-'0';
start=2;
}
else{
num=number[0]-'0';
start=1;
}
mul=(int) sqrt(num);
result[0]=mul+'0';
result[1]='\0';
if(num-mul*mul ==0)
extra[0]='\0';
else
sprintf(extra,"%d",num-mul*mul);
for(;start<len;start+=2){
e=strlen(extra);
extra[e]=number[start];
extra[e+1]=number[start+1];
extra[e+2]='\0';
two[0]='2';
two[1]='\0';
call_mult(result,two,left);
l=strlen(left);
for(mul=9;mul>=0;mul--){
who[0]=mul+'0';
who[1]='\0';
217
APPENDIX B
strcat(left,who);
call_mult(left,who,after);
if(call_minus(extra,after,temp)==1){
result[++r]=mul+'0';
result[r+1]='\0';
strcpy(extra,temp);
break;
}
else
left[l]='\0';
}
}
result[++r]='\0';
}
/******************************************************************/
int main(){
char fir[MAX],ex[MAX],res[MAX];
while(scanf("%s",&fir)==1){
call_sqrt(fir,res,ex);
int len=strlen(res);
for(int i=0;i<len;i++) printf("%c",res[i]);
printf("\n");
}
return 0;
}
Fibonacci Numbers
//* This run O(log n) time//
#include<stdio.h>
long conquer_fibonacci(long n){
long i,h,j,k,t;
i=h=1;
j=k=0;
while(n>0){
if(n%2==1){
t=j*h;
j=i*h + j*k +t;
i=i*k + t;
}
t=h*h;
h=2*k*h + t;
k=k*k + t;
n=(long) n/2;}
return j;}
int main(){
long n,res;
while(scanf("%ld",&n)==1){
res=conquer_fibonacci(n);
printf("%ld\n",res);}
return 0;
}
218
APPENDIX B
219
APPENDIX B
220
int n;
while(cin>>n)
{
cout<<"The Fibonacci number for "<<n<<" is "<<fibo[n]<<"\n";
}
return 0;
}
Input :
88
#.#.#.#.
........
#.#.....
#.##.#..
..#..##.
#..##...
...#...#
#.s#d.#.
#include<stdio.h>
#include<conio.h>
#include<values.h>
#define N 100
#define MAX MAXINT
int
int
int
int
APPENDIX B
221
nr = r + R[i], nc = c + C[i];
if(mat[nr][nc]==1)
{
if(cost[nr][nc]>cost[r][c]+1)
cost[nr][nc]=cost[r][c]+1, nQ(nr, nc, p);
}
}
} while (rear!=front);
leaf = p;
}
void show()
{
for(int i=0; i<=m; i++)
{
for(int j=0; j<=n; j++)
{
if(res[i][j])
printf("X");
else
printf(" ");
}
printf("\n");
}
}
void dfs(int leaf)
{
if(Q[leaf][2]==-1)
{
res[Q[leaf][0]][Q[leaf][1]] = 1;
return;
}
dfs(Q[leaf][2]);
res[Q[leaf][0]][Q[leaf][1]] = 1;
}
void main()
{
clrscr();
char ch;
freopen("maze.txt", "r", stdin);
scanf("%d%d", &m, &n);
getchar();
for(i=0; i<m; i++)
{
for(j=0; j<n; j++)
{
cost[i][j] = MAX;
scanf("%c", &ch);
if(ch=='#')
mat[i][j] = 0;
else if(ch=='.')
mat[i][j] = 1;
else if(ch=='s')
APPENDIX B
mat[i][j] = 2, sc = j, sr = i;
else
}
getchar();
mat[i][j] = 3, res[i][j] = 1;
}
bfs(sr, sc, -1);
dfs(leaf);
show();
}
MinSum (DFS/QUEUE)
Input :
5
3
6
5
8
3
6
4
1
9
4
7
1
8
3
1
2
2
2
9
3
1
8
7
9
2
2
6
4
5
6
3
Code
#include<stdio.h>
#include<conio.h>
#include<values.h>
#define N 100
#define MAX MAXINT
int mat[N][N], M[N][N], Q[N][4], front = -1, rear = -1;
int m, n, nc, nr, p, s, finalSum=MAX, leaf, r, c, i;
void init()
{
for(int i=0; i<N; i++)
for(int j=0; j<N; j++)
M[i][j] = MAX, mat[i][j] = 0;
}
void nQ(int r, int c, int p, int s)
{
Q[++rear][0] = r;
Q[rear][1] = c;
Q[rear][3] = s;}
void dQ(int *r, int *c, int *p, int *s)
{
*r = Q[++front][0];
*c = Q[front][1];
*p = front;
*s = Q[front][3];
}
Q[rear][2] = p;
222
APPENDIX B
223
void bfs()
{
for(r=0, c=0; r<m; r++)
nQ(r, c, -1, mat[r][c]);
do
{
dQ(&r, &c, &p, &s);
if(c<n-1)
for(i=-1; i<2; i++)
{
nr=(m+r+i)%m, nc=c+1;
if(M[nr][nc] > s+mat[nr][nc])
nQ(nr, nc, p, s+mat[nr][nc]), M[nr][nc] = s+mat[nr][nc];
}
else if(s<finalSum)
finalSum = s, leaf = p;
} while(rear!=front);
}
void dfs(int leaf)
{
if(Q[leaf][2]==-1)
{
printf(" <%d, %d>", Q[leaf][0]+1, Q[leaf][1]+1);
return;
}
dfs(Q[leaf][2]);
printf(" <%d, %d>", Q[leaf][0]+1, Q[leaf][1]+1);
}
void main()
{
clrscr();
int i, j, t;
init();
freopen("in.txt", "r", stdin);
scanf("%d%d", &m, &n);
for(i=0; i<m; i++)
for(j=0; j<n; j++)
{
scanf("%d", &t);
mat[i][j] = t;
}
bfs();
printf("Final sum: %d\nPath:", finalSum);
dfs(leaf);
}
APPENDIX B
224
Floyed Warshal
Input
5
1
1
1
2
2
3
4
0
7
2
3
5
5
4
2
5
0
4
1
6
3
1
1
1
Code :
#include<stdio.h>
#include<values.h>
#define N 100
#define INF MAXINT
int mat[N][N], path[N][N], n, e;
void initMat()
{
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
mat[i][j] = INF;
}
void initPath()
{
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
if(mat[i][j]!=INF)
path[i][j] = j;
else
path[i][j] = 0;
}
void floyd_warshall()
{
for(int k=1; k<=n; k++)
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
if(mat[i][k]!=INF && mat[k][j]!=INF)
if(mat[i][k]+mat[k][j] < mat[i][j])
mat[i][j] = mat[i][k] + mat[k][j],
path[i][j] = path[i][k];
APPENDIX B
}
void showPath(int i, int j)
{
if(i==j)
{
printf("->%d", i);
return;
}
printf("->%d", i);
showPath(path[i][j], j);
}
void main()
{
while(scanf("%d%d", &n, &e) && n && e)
{
initMat();
for(int i, j, c, k=0; k<e; k++)
{
scanf("%d%d%d", &i, &j, &c);
mat[i][j] = c;
}
initPath();
floyd_warshall();
for(i=1; i<=n; i++)
{
for(j=1; j<=n; j++)
if(path[i][j])
{
printf("%d", i);
showPath(path[i][j], j);
printf("\n");
}
printf("\n");
}
}
}
Graph Coloring
#include<stdio.h>
int a[20][20],x[20],n,m;
void next(int k)
{
int j;
while(1)
225
APPENDIX B
226
{
x[k]=(x[k]+1)%(m+1);
if(x[k]==0)
return;
for(j=1;j<=n;j++)
if(a[k][j]!=0&&x[k]==x[j])
break;
if(j==n+1)
return;
}
}
void mcolor(int k)
{
int j;
while(1)
{
next(k);
if(x[k]==0)
return;
if(k==n)
{
printf("
");
for(j=1;j<=n;j++)
printf("%2d",x[j]);
}
else
mcolor(k+1);
}
}
void main()
{
int i,u,v;
printf("\n\n Enter how many colors : ");
scanf("%d",&m);
printf("\n\n Enter how many nodes(0<n<20) :");
scanf("%d",&n);
printf("\n\n Enter your edges(ex- u sp v)(press 'e' for end) : \n");
for(i=1;i<=(n*n)/2;i++)
{
if(getchar()=='e')
break;
scanf("%d%d",&u,&v);
a[u][v]=a[v][u]=1;
}mcolor(1); printf("\n\n");}
APPENDIX B
227
while(1)
{
x[k]=(x[k]+1)%(n+1);
if(x[k]==0)
return;
if((a[x[k-1]][x[k]])!=0)
{
for(j=1;j<=k-1;j++)
if(x[k]==x[j])
break;
if(j==k)
if((k<n)||(k==n&&a[x[n]][x[1]]!=0))
return;
}
}
}
void hamilt(int k)
{
int j;
while(1)
{
next(k);
if(x[k]==0)
return;
if(k==n)
{
printf("
");
for(j=1;j<=n;j++)
printf("%2d",x[j]);
}
else
hamilt(k+1);
}
}
void main()
{
int i,u,v;
x[1]=1;
printf("\n\n Enter how many nodes(0<n<20) :");
scanf("%d",&n);
printf("\n\n Enter your edges(ex- u sp v)(press 'e' for end) : \n");
for(i=1;i<=(n*n)/2;i++)
{
if(getchar()=='e')
break;
scanf("%d%d",&u,&v);
a[u][v]=a[v][u]=1;
}
hamilt(2);
printf("\n\n");
}
APPENDIX B
228
APPENDIX B
b[i][k]=0;
}
for(j=1,i=1;b[1][j]!=0;j++)
{
k=b[1][j];
if(b[k][2])
i++;
}
if(j==i)
f=1;
art(1,1);
at[s]=-9;
printf("\n\n Articulation points are : ");
if(!f)
for(i=1;at[i]!=-9;i++)
printf("%3d",at[i]);
if(f)
for(i=1;at[i]!=1;i++)
printf("%3d",at[i]);
printf("\n\n");
}
229
APPENDIX C
INTRODUCTION TO STL
230
APPENDIX C
STANDARD TEMPLETE LIBRARY (STL)
The programming languages for the contest will be C, C++, Pascal, and
Java and the scanf()/printf() family of functions. The C++ string library and
Standard Template Library (STL) is also available. This part of this book
contains an introductory note about STL[9] .
APPENDIX C
INTRODUCTION TO STL
231
The Standard Template Library, or STL, is a C++ library of container classes, algorithms,
and iterators; it provides many of the basic algorithms and data structures of computer
science. The STL is a generic library, meaning that its components are heavily
parameterized: almost every component in the STL is a template. You should make sure
that you understand how templates work in C++ before you use the STL.
Containers and algorithms
Like many class libraries, the STL includes container classes: classes whose purpose is to
contain other objects. The STL includes the classes vector, list, deque, set, multiset, map,
multimap, hash_set, hash_multiset, hash_map, and hash_multimap. Each of these classes
is a template, and can be instantiated to contain any type of object. You can, for example,
use a vector<int> in much the same way as you would use an ordinary C array, except
that vector eliminates the chore of managing dynamic memory allocation by hand.
vector<int> v(3);
v[0] = 7;
v[1] = v[0] + 3;
v[2] = v[0] + v[1];
The STL also includes a large collection of algorithms that manipulate the data stored in
containers. You can reverse the order of elements in a vector, for example, by using the
reverse algorithm.
reverse(v.begin(), v.end()); // v[0] == 17, v[1] == 10, v[2] == 7
There are two important points to notice about this call to reverse. First, it is a global
function, not a member function. Second, it takes two arguments rather than one: it
operates on a range of elements, rather than on a container. In this particular case the
range happens to be the entire container v.
The reason for both of these facts is the same: reverse, like other STL algorithms, is
decoupled from the STL container classes.
double A[6] = { 1.2, 1.3, 1.4, 1.5, 1.6, 1.7 };
reverse(A, A + 6);
for (int i = 0; i < 6; ++i)
cout << "A[" << i << "] = " << A[i];
This example uses a range, just like the example of reversing a vector: the first argument
to reverse is a pointer to the beginning of the range, and the second argument points one
APPENDIX C
INTRODUCTION TO STL
232
element past the end of the range. This range is denoted [A, A + 6); the asymmetrical
notation is a reminder that the two endpoints are different, that the first is the beginning
of the range and the second is one past the end of the range.
Website for downloading STL
http://www.sgi.com/tech/stl/download.htm
Individual files in STL
algo.h
hash_
map.h
numeric
stdexcept
stl_heap.h
stl_slist.h
algobase.h
hash_s
et
pair.h
stl_algo.h
stl_iterator.h
stl_stack.h
algorithm
hash_s
et.h
pthread_alloc
stl_algoba
se.h
stl_iterator_ba
se.h
stl_string_f
wd.h
alloc.h
hashta
ble.h
pthread_alloc.
h
stl_alloc.h
stl_list.h
stl_tempbu
f.h
bitset
heap.h
queue
stl_bvecto
r.h
stl_map.h
stl_threads
.h
bvector.h
iterator
rope
stl_config.
h
stl_multimap.h
stl_tree.h
char_traits.h
iterator.
h
rope.h
stl_constr
uct.h
stl_multiset.h
stl_uninitial
ized.h
concept_chec
ks.h
limits
ropeimpl.h
stl_ctraits
_fns.h
stl_numeric.h
stl_vector.h
container_con
cepts.h
list
sequence_con
cepts.h
stl_deque.
h
stl_pair.h
string
defalloc.h
list.h
set
stl_except
ion.h
stl_queue.h
tempbuf.h
deque
map
set.h
stl_functio
n.h
stl_range_error
s.h
tree.h
deque.h
map.h
slist
stl_hash_f
un.h
stl_raw_storag
e_iter.h
type_traits.
h
function.h
memor
y
slist.h
stl_hash_
map.h
stl_relops.h
utility
functional
multima
p.h
stack
stl_hash_
set.h
stl_rope.h
valarray
hash_map
multiset
.h
stack.h
stl_hashta
ble.h
stl_set.h
vector
APPENDIX C
INTRODUCTION TO STL
233
Search
const
const
const
const
Queue
int main() {
queue<int> Q;
Q.push(8);
Q.push(7);
Q.push(6);
Q.push(2);
assert(Q.size() == 4);
assert(Q.back() == 2);
assert(Q.front() == 8);
Q.pop();
assert(Q.front() == 7);
Q.pop();
assert(Q.front() == 6);
Q.pop();
assert(Q.front() == 2);
Q.pop();
assert(Q.empty());}
APPENDIX C
INTRODUCTION TO STL
234
Sort
int A[] = {1, 4, 2, 8, 5, 7};
const int N = sizeof(A) / sizeof(int);
sort(A, A + N);
copy(A, A + N, ostream_iterator<int>(cout, " "));
// The output is " 1 2 4 5 7 8".
Complexity
O(N log(N)) comparisons (both average and worst-case), where N is last first.
Binary Search
int main()
{
int A[] = { 1, 2, 3, 3, 3, 5, 8 };
const int N = sizeof(A) / sizeof(int);
for (int i = 1; i <= 10; ++i) {
cout << "Searching for " << i << ": "
<< (binary_search(A, A + N, i) ? "present" : "not present") <<
endl;
}
}
The output
Searching
Searching
Searching
Searching
Searching
Searching
Searching
Searching
Searching
Searching
for
for
for
for
for
for
for
for
for
for
1: present
2: present
3: present
4: not present
5: present
6: not present
7: not present
8: present
9: not present
10: not present
APPENDIX D
235
APPENDIX D
PC CONTEST ADMINISTRATION AND TEAM GUIDE
2
APPENDIX D
236
PC2 operates using a client-server architecture. Each site in a contest runs a single PC2
server, and also runs multiple PC2 clients which communicate with the site server.
Logging into a client using one of several different types of PC2 accounts (Administrator,
Team, Judge, or Scoreboard) enables that client to perform common contest operations
associated with the account type, such as contest configuration and control
(Administrator), submitting contestant programs (Team), judging submissions (Judge),
and maintaining the current contest standings (Scoreboard).
PC2 clients communicate only with the server at their site, regardless of the number of
sites in the contest. In a multi-site contest, site servers communicate not only with their
own clients but also with other site servers, in order to keep track of global contest state.
The following communication requirements must therefore be met in order to run a
contest using PC2: (1) a machine running a PC2 server must be able to communicate via
TCP/IP with every machine running a PC2 client at its site; and (2) in a multi-site contest,
every machine running a PC2 server must be able to communicate via TCP/IP with the
machines running PC2 servers at every other site1[1]. In particular, there must not be any
firewalls which prohibit these communication paths; the system will not operate if this
communication is blocked. It is not necessary for client machines to be able to contact
machines at other sites.
Each PC2 module (server or client) reads one or more .ini initialization files when it starts;
these files are used to configure the module at startup. The client module also tailors its
configuration when a user (Team, Judge, etc.) logs in. In a typical PC2 contest
configuration, each Team, Judge, etc. uses a separate physical machine, and each of these
machines runs exactly one client module.It is possible to have multiple clients running on
the same physical machine, for example by having different users logging in to different
accounts on a shared machine. In this case, each user (Team, Judge, etc.) will be
executing their own Java Virtual Machine (JVM), and must have their own separate
directory structure including their own separate copy of the PC2 initialization files in
their account.
PC2 Setup for Administrator
For those people who hate to read manuals and would rather take a chance with a shortcut
list, here is a very terse summary of the steps necessary to install PC2 and get it running.
Please note that this is provided as a convenience for geniuses (or gluttons for
punishment). The remainder of the manual was written to help everyone else. If you have
APPENDIX D
237
problems after following this list, please read the rest of the manual before sending us a
request for help.
Install PC2 by unzipping the PC2 distribution to the PC2 installation directory;
Add the Java bin directory and the PC2 installation directory to the PATH;
Modify the sitelist.ini file as necessary to specify each site server name.
Edit the pc2v8.ini file to point servers and clients to the server IP:port and to
specify the appropriate site server name; put the modified .ini file on every server and
client machine;
Start a PC2 server using the command pc2server and answer the prompted
question.
Start a PC2 Admin client using the command pc2admin and login using the name
root and password root.
APPENDIX D
238
Problems (create one or more contest problems, specifying the problem input
data file if there is one);
APPENDIX D
Press
239
a PC2 client on each Team and Judge machine and log in using the Admincreated accounts and passwords.
Start
a PC2 client on the Scoreboard machine and log in using the board1
Scoreboard account/password; arrange for the scoreboard-generated HTML files to
be accessible to users browsers.
Start
This guide is intended to familiarize you with the process of submitting programs to
Contest Judges using the PC2 (P-C-Squared) Programming Contest Control system.
Starting PC2 will bring up the PC2 login screen, shown below:
APPENDIX D
240
To login to PC2, click once on the Name box on the login screen, enter your assigned
team ID, press the TAB key or click on the Password box, then enter your assigned
password. Your team ID will be of the form teamxx, where xx is your assigned team
number (for example, team3 or team12). After entering your team name and
password, click on the Logon button.
Submitting a Program to the Judges
Once the system accepts your login, you will be at the PC2 Main Menu screen, shown
below. Note that the team ID (team1 in this case) and the teams site location (CSUS
in this case) are displayed in the title bar.
APPENDIX D
241
Clicking on the SUBMIT tab near the top of the screen displays the Submit Run screen,
which is shown above.
Clicking in the Problem field will display a list of the contest problems; choose the
problem for which you wish to submit a program (run) to the Judges (in the example, a
problem named Bowling has been chosen).
Clicking in the Language field will display a list of the programming languages allowed
in the contest; choose the language used by the program that you wish to submit to the
Judges (in the example, Java has been chosen).
To submit a program to the Judges, you must specify the name of the file containing your
main program. Click on the Select button to invoke the File Dialog which lets you
locate and select your main file. The Dialog lets you automatically navigate to the correct
path and file location (in the example, the main program file C:\work\bowling.java has
been selected).
If your program consists of more than one file, you must enter the additional file names
in the Additional Files box. Click the Add button to invoke the dialog which lets you
locate and select your additional files; select a file in the box and click the Remove
button to remove a previously-selected file.
Important: you must specify the name of your main program file in the Main File field,
not in the Additional Files box! Select only source code files for submission to the
Judges. Do not submit data files or executable files.
PC2 Uninstall
To uninstall PC2 it is only necessary to undo the above installation steps; that is,
remove the $PC2HOME directory and its contents and restore the system environment
variables to their former values . PC2 itself does not make any changes to any machine
locations outside those listed above either during installation or execution. In particular,
for example, it makes no entries in the registry in a Windows environment, nor does it
copy any files to locations outside the installation directories in any environment.
APPENDIX E
242
APPENDIX E
IMPORTANT WEBSITES/ FOR ACM/ICPC PROGRAMMERS
Now a days the world is open for learners and the Internet makes the world
inside our room. There are many websites now on the Internet for the
beginners as well as programmers. Some sites are for contest and tutorial,
some for books, some sites are for programming language. Mathematics is
one of the essential for programming and there are a lot of mathematical
site in the net. The pioneers also publish their ideas and advice on the Internet for us. In
this page you will find the link of those pages.[10]
APPENDIX E
243
APPENDIX E
244
http://contest.uvarov.ru/
This is the POTM master's home page. POTM Contest means Programmer of the Month
Contest. The problem set of this contest is different then the conventional programming
contest. The organizer gives more stress on Optimization than number of solution.
http://www.acmbeginner.tk
Is it very difficult to disclose oneself as a good programmer? To solve the problems, the
difficulty that you face in the 24-hour online judge and the help and guideline that found
to overcome them is integrated in this site "ACMBEGINNER" by M H Rasel.
http://groups.yahoo.com/group/icpc-l
http://groups.yahoo.com/group/acm_solver
You talk about algorithms, data structures and mathematical concepts. The group is made
for teams, ex-teams and everybody interested in on-line programming. Coaches and
teachers are very welcome.
Site of Pioneers !
APPENDIX E
245
Books
APPENDIX E
246
Number Theory
Number Theory by S G Telang is a book, consists of lot of knowledge about the number
theory. It is better idea to read this book before reading the book Concrete Mathematics.
This is easy to understand.
Discrete Mathematics And Its Application
Discrete Mathematics And Its Application by Kenneth H. Rosen consists of a lot of
practical help on integer matrices, mathematical reasoning, counting, graph tree
problems.
Data Structure Using C and C++
Data structure using C and C++ by ,Yedidyah Langsam, Moshe J. Augenstein Aaron M.
Tenenbaum. Second Edition. This book contains basic problem related to Data Structures
with C coding.
Programming Challenges
Programming Challenges, by Steven Skiena Miguel Revilla. We dont want to say
anything about this two legend. All the programmers are familiar with this two ultimate
Programming Contest Legends. Use this book to learn what to do for the programming
contest.
Art of Programming Contest
Well, Art of Programming Contest is this one, by Ahmed Shamsul Arefin.
http://www.sgi.com/tech/stl/
In this site you will find the STL documentation. The STL is very important for
programming. It is efficient and make code simple and sort. To use this the C++ template
knowledge is necessary. The beginner can overlook the STL at beginning but is is needed
in future.
APPENDIX E
247
www.cplusplus.com / www.cprogramming.com
Great sites for the C/C++ programmers. These sites contains documents, References,
sources codes with electronic forum where you can consult with great programmers.
Mathematics Site
mathworld.wolfram.com
MathWorld is a comprehensive and interactive mathematics encyclopedia intended for
students, educators, math enthusiasts, and researchers. Like the vibrant and constantly
evolving discipline of mathematics, this site is continuously updated to include new
material and incorporate new discoveries.
http://mathforum.org/
The Math Forum is a leading center for mathematics and mathematics education on the
Internet. Its mission is to provide resources, materials, activities, person-to-person
interactions, and educational products and services that enrich and support teaching and
learning in an increasingly technological world.
http://www.math.com/
Math.com is dedicated to providing revolutionary ways for students, parents, teachers,
and everyone to learn math. Combining educationally sound principles with proprietary
technology, Math.com offers a unique experience that quickly guides the user to the
solutions they need and the products they want.
http://www.math-net.org/
Math-Net intends to coordinate the electronic information and communication activities
of the global mathematical community with the aim to enhance the free-flow of
information within the community.
REFERENCES:
248
REFERENCES
INDEX
249
INDEX
ADHOC problems, 16
Adjacency List, 139
Adjacency Matrix, 139
Algorithm, 19
Array, 74
Base Number Conversion, 91
Bellman-Ford Algorithm, 164
Big Integer, 92
Big Mod, 91, 195
Binary Search, 113
Binary Search Tree, 113
Breadth-first search, 144
BRUTE FORCE METHOD, 85
Bubble Sort, 107
Carmichael Number, 93
Collision Handling, 115
Combinations, 202
COMPILATION ERROR (CE), 15
Connected Fields, 158
Connectedness, 141
Convex Hull, 173
Counting Change, 131
Counting Combinations, 94
Counting Sort, 111
DATA STRUCTRURES, 72
debugging, 15
Decimal To Roman, 198
Decomposition, 89
Depth First with Iterative Deepening, 150
Depth-first search, 147
Dictionary, 114
Dijkstra Algorithm, 163
Directed Acyclic Graph, 165
Directed Graph, 137
Divide and Conquer, 88
Divisors and Divisibility, 95
DYNAMIC PROGRAMMING, 121
Earth coordinate system, 172
Edge List, 138
Edit Distance, 127
Euclids Algorithm, 190
Euler Cycle, 170
Euler Path, 170
Exponentiation, 96
Factorial, 97
Fermat Algorithm, 104
Fermat Little Test:, 104
Fibonacci, 97
Floyd Warshall, 165
GCD, 191
Graph Transpose, 170
GRAPHS, 134
Greatest Common Divisor (GCD), 99
GREEDY ALGORITHMS, 117