Chapter 2.2: Control Flow
π Prerequisites: Chapter 2.1 (variables, cin/cout, basic arithmetic)
2.2.0 What is "Control Flow"?
So far, every program we wrote ran top to bottom β line 1, line 2, line 3, done. Like reading a book straight through.
But real programs need to make decisions and repeat things. That's what "control flow" means β controlling the flow (order) of execution.
Think of it like a "Choose Your Own Adventure" book:
- Sometimes you're told "if you want to fight the dragon, turn to page 47; otherwise turn to page 52"
- Sometimes you're told "repeat this section until you escape the dungeon"
C++ gives us exactly this with:
if/elseβ make decisions based on conditionsfor/whileloops β repeat a section of code
Here's a visual overview:
In the loop diagram: the program keeps going back to Step 2 until the condition becomes false, then it exits to Step 3.
2.2.1 The if Statement
The if statement lets your program make a decision: "if this condition is true, do this thing."
Basic if
#include <bits/stdc++.h>
using namespace std;
int main() {
int score;
cin >> score;
if (score >= 90) {
cout << "Excellent!\n";
}
cout << "Done.\n"; // always runs regardless of score
return 0;
}
If score is 95: prints Excellent! then Done.
If score is 80: prints only Done. (the if-block is skipped)
if / else
int score;
cin >> score;
if (score >= 60) {
cout << "Pass\n";
} else {
cout << "Fail\n";
}
The else block runs only when the if condition is false. Exactly one of the two blocks will run.
if / else if / else Chains
When you have multiple conditions to check:
int score;
cin >> score;
if (score >= 90) {
cout << "A\n";
} else if (score >= 80) {
cout << "B\n";
} else if (score >= 70) {
cout << "C\n";
} else if (score >= 60) {
cout << "D\n";
} else {
cout << "F\n";
}
C++ checks these conditions in order, from top to bottom, and runs the first one that's true. Once it runs one block, it skips all the remaining else if/else blocks.
So if score = 85:
- Is 85 >= 90? No β skip
- Is 85 >= 80? Yes β print "B", then jump past all the else-ifs
π€ Why does this work? When we reach
else if (score >= 80), we already know score < 90 (because if it were β₯ 90, the first condition would have caught it). Eachelse ifimplicitly assumes all the previous conditions were false.
Comparison Operators
| Operator | Meaning | Example |
|---|---|---|
== | Equal to | a == b |
!= | Not equal to | a != b |
< | Less than | a < b |
> | Greater than | a > b |
<= | Less than or equal to | a <= b |
>= | Greater than or equal to | a >= b |
Logical Operators (Combining Conditions)
| Operator | Meaning | Example |
|---|---|---|
&& | AND β both must be true | x > 0 && y > 0 |
|| | OR β at least one must be true | x == 0 || y == 0 |
! | NOT β flips true to false | !finished |
int x, y;
cin >> x >> y;
if (x > 0 && y > 0) {
cout << "Both positive\n";
}
if (x < 0 || y < 0) {
cout << "At least one is negative\n";
}
bool done = false;
if (!done) {
cout << "Still working...\n";
}
π Common Bug: = vs ==
This is one of the most common mistakes for beginners (and even experienced programmers!):
int x = 5;
// DANGEROUS BUG:
if (x = 10) { // This ASSIGNS 10 to x, doesn't compare!
// x becomes 10, and since 10 is nonzero, this is always TRUE
cout << "x is 10\n"; // This ALWAYS runs, even though x started as 5!
}
// CORRECT:
if (x == 10) { // This COMPARES x with 10
cout << "x is 10\n"; // Only runs when x actually equals 10
}
The = operator assigns (stores a value). The == operator compares (checks if two values are equal). They look similar but do completely different things.
β‘ Pro Tip: Some programmers write
10 == xinstead ofx == 10β if you accidentally type=instead of==, it becomes10 = xwhich is a compile error (you can't assign to a literal). This is called a "Yoda condition."
Nested if Statements
You can put if statements inside other if statements:
int age, income;
cin >> age >> income;
if (age >= 18) {
cout << "Adult\n";
if (income > 50000) {
cout << "High income adult\n";
} else {
cout << "Standard income adult\n";
}
} else {
cout << "Minor\n";
}
Be careful: each else matches the nearest preceding if that doesn't already have an else.
2.2.2 The while Loop
A while loop repeats a block of code as long as its condition is true. When the condition becomes false, execution continues after the loop.
while (condition) {
body (runs over and over)
}
#include <bits/stdc++.h>
using namespace std;
int main() {
int i = 1; // 1. Initialize before the loop
while (i <= 5) { // 2. Check condition β if false, skip the loop
cout << i << "\n"; // 3. Run the body
i++; // 4. Update β VERY IMPORTANT! Forget this β infinite loop
}
// After loop: i = 6, condition 6 <= 5 is false, loop exits
return 0;
}
Output:
1
2
3
4
5
π Common Bug: Infinite Loop
If you forget to update the variable (step 4 above), the condition never becomes false and the loop runs forever!
int i = 1;
while (i <= 5) {
cout << i << "\n";
// BUG: forgot i++ β this prints "1" forever!
}
If your program seems stuck, press Ctrl+C to stop it.
When to use while vs for
- Use
whilewhen you don't know in advance how many iterations you need - Use
forwhen you do know the count (we'll coverfornext)
Classic while use case: read until a condition is met.
// Common USACO pattern: read until end of input
int x;
while (cin >> x) { // cin >> x returns false when input runs out
cout << x * 2 << "\n";
}
do-while Loop
A do-while loop always runs its body at least once, then checks the condition:
int n;
do {
cin >> n;
} while (n <= 0); // keep re-reading until user gives a positive number
This is useful when you want to execute something before checking whether to repeat. It's rare in competitive programming but worth knowing.
2.2.3 The for Loop
The for loop is the most used loop in competitive programming. It packages initialization, condition-check, and update into one clean line:
for (initialization; condition; update) {
body
}
This is equivalent to:
initialization;
while (condition) {
body
update;
}
Visual: For Loop Flowchart
The flowchart above traces the execution: initialization runs once, then the condition is checked before every iteration. When false, the loop exits.
Common for Patterns
// Count from 0 to 9 (standard competitive programming pattern)
for (int i = 0; i < 10; i++) {
cout << i << " ";
}
// Prints: 0 1 2 3 4 5 6 7 8 9
// Count from 1 to n (inclusive)
int n = 5;
for (int i = 1; i <= n; i++) {
cout << i << " ";
}
// Prints: 1 2 3 4 5
// Count backwards
for (int i = 10; i >= 1; i--) {
cout << i << " ";
}
// Prints: 10 9 8 7 6 5 4 3 2 1
// Count by steps of 2
for (int i = 0; i <= 10; i += 2) {
cout << i << " ";
}
// Prints: 0 2 4 6 8 10
π§ Loop Tracing: Understanding Exactly What Happens
When learning loops, trace through them manually. Here's how:
Code: for (int i = 0; i < 4; i++) cout << i * i << " ";
Practice tracing loops on paper before running them β it builds intuition and helps spot bugs.
The Most Common USACO Loop Pattern
Read N numbers and process each one:
int n;
cin >> n;
for (int i = 0; i < n; i++) {
int x;
cin >> x;
// process x here
cout << x * 2 << "\n";
}
β‘ Pro Tip: In competitive programming,
for (int i = 0; i < n; i++)with 0-based indexing is standard. It matches how arrays are indexed (Chapter 2.3), so everything lines up neatly.
2.2.4 Nested Loops
You can put a loop inside another loop. The inner loop runs completely for each single iteration of the outer loop.
// Print a 4x4 multiplication table
for (int i = 1; i <= 4; i++) { // outer: rows
for (int j = 1; j <= 4; j++) { // inner: columns
cout << i * j << "\t"; // \t = tab character
}
cout << "\n"; // newline after each row
}
Output:
1 2 3 4
2 4 6 8
3 6 9 12
4 8 12 16
Tracing the first two rows:
i=1: j=1βprint 1, j=2βprint 2, j=3βprint 3, j=4βprint 4, then newline
i=2: j=1βprint 2, j=2βprint 4, j=3βprint 6, j=4βprint 8, then newline
...
β οΈ Nested Loop Time Complexity
π‘ Why should you care about loop counts? In competitions, your program typically needs to finish within 1-2 seconds. A modern computer can execute roughly 10^8 to 10^9 simple operations per second. So if you can estimate how many times your loop body executes in total, you can determine whether it will exceed the time limit (TLE). This is the core idea behind "time complexity analysis" β we'll study it in greater depth in later chapters.
A single loop of N iterations does N operations. Two nested loops of N do N Γ N = NΒ² operations.
| Loops | Operations | Safe for N β€ | Example |
|---|---|---|---|
| 1 | N | ~10^8 | Iterating through an array to compute a sum |
| 2 (nested) | NΒ² | ~10^4 | Comparing all pairs |
| 3 (nested) | NΒ³ | ~450 | Enumerating all triplets |
If N = 1000 and you have two nested loops, that's 10^6 operations β fine. But if N = 100,000, that's 10^10 β too slow!
π§ Quick Rule of Thumb: After seeing the range of N, use the table above to work backwards and determine the maximum number of nested loops you can afford. For example, N β€ 10^5 β you can only use O(N) or O(N log N) algorithms; N β€ 5000 β O(NΒ²) is acceptable. This technique is extremely useful in USACO!
2.2.5 Switch Statements
When you have a variable and want to check many specific values, switch is cleaner than a long chain of if/else if:
int day;
cin >> day;
switch (day) {
case 1:
cout << "Monday\n";
break; // IMPORTANT: break exits the switch
case 2:
cout << "Tuesday\n";
break;
case 3:
cout << "Wednesday\n";
break;
case 4:
cout << "Thursday\n";
break;
case 5:
cout << "Friday\n";
break;
case 6:
case 7:
cout << "Weekend!\n"; // cases 6 and 7 share this code
break;
default:
cout << "Invalid day\n"; // runs if no case matches
}
When to use switch vs if-else
Use switch when... | Use if-else when... |
|---|---|
| Checking one variable against exact integer/char values | Comparing ranges (x > 10, x < 5) |
| 3+ specific values to check | Only 1-2 conditions |
| Cases are mutually exclusive | Complex boolean logic |
π Common Bug: Forgetting
breakβ Withoutbreak, execution "falls through" to the next case!
int x = 2;
switch (x) {
case 1:
cout << "one\n";
case 2:
cout << "two\n"; // this runs
case 3:
cout << "three\n"; // ALSO runs (fall-through!) because no break after case 2
}
// Output: two\nthree\n (surprising!)
2.2.6 break and continue
break β Exit the Loop Immediately
// Find the first number divisible by 7 between 1 and 100
for (int i = 1; i <= 100; i++) {
if (i % 7 == 0) {
cout << "First multiple of 7: " << i << "\n"; // prints 7
break; // stop searching β we found it
}
}
continue β Skip to the Next Iteration
// Print all numbers 1 to 10 except multiples of 3
for (int i = 1; i <= 10; i++) {
if (i % 3 == 0) {
continue; // skip the rest of this iteration, go to i++
}
cout << i << " ";
}
// Output: 1 2 4 5 7 8 10
break in Nested Loops
break only exits the innermost loop. To exit multiple levels, use a flag variable:
bool found = false;
int target = 25;
for (int i = 0; i < 10 && !found; i++) { // outer loop also checks !found
for (int j = 0; j < 10; j++) {
if (i * j == target) {
cout << i << " * " << j << " = " << target << "\n";
found = true;
break; // exits inner loop; outer loop exits too because of !found
}
}
}
2.2.7 Classic Loop Patterns in Competitive Programming
These patterns appear in nearly every USACO solution. Learn them cold.
Pattern 1: Read N Numbers, Compute Sum
int n;
cin >> n;
long long sum = 0;
for (int i = 0; i < n; i++) {
int x;
cin >> x;
sum += x;
}
cout << sum << "\n";
Complexity Analysis:
- Time: O(N) β iterate through N numbers, each processed in O(1)
- Space: O(1) β only one accumulator variable
sum
Pattern 2: Find Maximum (and Minimum) in a List
int n;
cin >> n;
int maxVal, minVal;
cin >> maxVal; // read first element
minVal = maxVal; // initialize both max and min to first element
for (int i = 1; i < n; i++) { // start from 2nd element (index 1)
int x;
cin >> x;
if (x > maxVal) maxVal = x;
if (x < minVal) minVal = x;
}
cout << "Max: " << maxVal << "\n";
cout << "Min: " << minVal << "\n";
Complexity Analysis:
- Time: O(N) β iterate through N numbers, each comparison in O(1)
- Space: O(1) β only two variables
maxValandminVal
π€ Why initialize to the first element? Don't initialize max to 0! What if all numbers are negative? Initializing to the first element guarantees we start with a real value from the input.
Pattern 3: Count How Many Satisfy a Condition
int n;
cin >> n;
int count = 0;
for (int i = 0; i < n; i++) {
int x;
cin >> x;
if (x % 2 == 0) { // condition: even number
count++;
}
}
cout << "Even count: " << count << "\n";
Pattern 4: Print a Star Triangle Pattern
int n;
cin >> n;
for (int row = 1; row <= n; row++) { // row goes from 1 to n
for (int col = 1; col <= row; col++) { // print `row` stars per row
cout << "*";
}
cout << "\n"; // newline after each row
}
For n=4, output:
*
**
***
****
Pattern 5: Compute Sum of Digits
int n;
cin >> n;
int digitSum = 0;
while (n > 0) {
digitSum += n % 10; // last digit
n /= 10; // remove last digit
}
cout << digitSum << "\n";
Tracing for n = 12345:
n=12345: digitSum += 5, n becomes 1234
n=1234: digitSum += 4, n becomes 123
n=123: digitSum += 3, n becomes 12
n=12: digitSum += 2, n becomes 1
n=1: digitSum += 1, n becomes 0
n=0: loop exits. digitSum = 15 β
2.2.8 Complete Example: USACO-Style Problem
Problem: You have N cows. Each cow has a milk production rating. Find the highest-rated cow's rating and count how many cows produce above-average milk.
#include <bits/stdc++.h>
using namespace std;
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int n;
cin >> n;
// We need to store all values to compare against the average
// (We'll learn arrays/vectors in Chapter 2.3 β for now use two passes)
// First pass: find sum and max
long long sum = 0;
int maxMilk = 0;
vector<int> milk(n); // store all values (preview of Chapter 2.3)
for (int i = 0; i < n; i++) {
cin >> milk[i];
sum += milk[i];
if (milk[i] > maxMilk) maxMilk = milk[i];
}
double avg = (double)sum / n;
// Second pass: count above-average
int aboveAvg = 0;
for (int i = 0; i < n; i++) {
if (milk[i] > avg) aboveAvg++;
}
cout << "Maximum: " << maxMilk << "\n";
cout << "Above average: " << aboveAvg << "\n";
return 0;
}
Sample Input:
5
10 20 30 40 50
Sample Output:
Maximum: 50
Above average: 2
(Average is 30; cows with 40 and 50 are above average β 2 cows)
Complexity Analysis:
- Time: O(N) β two passes (read + count), each O(N), total O(2N) = O(N)
- Space: O(N) β uses
vector<int> milk(n)to store all data
β οΈ Common Mistakes in Chapter 2.2
| # | Mistake | Example | Why It's Wrong | Fix |
|---|---|---|---|---|
| 1 | Confusing = with == | if (x = 10) | = is assignment, not comparison; result is always true | Use == for comparison |
| 2 | Forgetting i++ causing infinite loop | while (i < n) { ... } without i++ | Condition is always true, program hangs | Ensure the loop variable is updated |
| 3 | Forgetting break in switch | case 2: cout << "two"; without break | Execution "falls through" to the next case | Add break; at the end of each case |
| 4 | Off-by-one error | for (int i = 0; i <= n; i++) should be < n | Loops one extra time, may go out of bounds or overcount | Carefully verify < vs <= |
| 5 | Initializing max to 0 | int maxVal = 0; when all numbers are negative | 0 is larger than all inputs, result is wrong | Initialize to the first element or INT_MIN |
| 6 | Reusing the same variable name in nested loops | Outer for (int i...) and inner for (int i...) | Inner i shadows outer i, causing unexpected outer loop behavior | Use different variable names for inner and outer loops (e.g., i and j) |
Chapter Summary
π Key Takeaways
| Concept | Syntax | When to Use | Why It Matters |
|---|---|---|---|
if | if (cond) { ... } | Execute when a condition is true | Foundation of program decisions; used in almost every problem |
if/else | if (...) {...} else {...} | Choose between two options | Handles yes/no type decisions |
if/else if/else | chained | Choose among multiple options | Grading scales, classification scenarios |
while | while (cond) {...} | Repeat when count is unknown | Reading until end of input, simulating processes |
for | for (int i=0; i<n; i++) {...} | Repeat when count is known | Most commonly used loop in competitive programming |
| Nested loops | Loop inside loop | Need to iterate over all pairs | Watch out for O(NΒ²) complexity limits |
break | break; | Exit immediately after finding target | Early termination saves time |
continue | continue; | Skip current iteration | Filter out elements that don't need processing |
switch | switch(x) { case 1: ... } | Check one variable against multiple exact values | Cleaner code than long if-else chains |
&& / || / ! | logical operators | Combine multiple conditions | Building blocks for complex decisions |
π§© Five Classic Loop Patterns Quick Reference
| Pattern | Purpose | Complexity | Section |
|---|---|---|---|
| Read N + Sum | Read N numbers and compute their sum | O(N) | 2.2.7 Pattern 1 |
| Find Max/Min | Find the maximum/minimum value | O(N) | 2.2.7 Pattern 2 |
| Count Condition | Count how many elements satisfy a condition | O(N) | 2.2.7 Pattern 3 |
| Star Triangle | Print patterns using nested loops | O(NΒ²) | 2.2.7 Pattern 4 |
| Digit Sum | Extract and sum individual digits | O(logββN) | 2.2.7 Pattern 5 |
β FAQ (Frequently Asked Questions)
Q1: Can for and while replace each other? When should I use which?
A: Yes, any
forloop can be rewritten as awhileloop, and vice versa. Rule of thumb: if you know the number of iterations (e.g., "loop N times"), usefor; if you don't know the count (e.g., "read until end of input"), usewhile. In competitions,foris used about 90% of the time.
Q2: How many levels deep can nested loops go? Is there a limit?
A: Syntactically there's no limit, but in practice you should be cautious beyond 3 levels. Two nested loops give O(NΒ²), three give O(NΒ³). When N β₯ 1000, three nested loops can easily time out. If you find yourself needing more than 3 levels of nesting, it usually means you need a more efficient algorithm (covered in later chapters).
Q3: break only exits the innermost loop. How do I break out of multiple nested loops at once?
A: Two common approaches: β Use a
bool found = falseflag variable, and have the outer loop also check!found; β‘ Wrap the nested loops in a function and usereturnto exit directly. Approach β is more common β see Section 2.2.6 for a complete example.
Q4: Which is faster, switch or if-else if?
A: For a small number of cases (< 10), performance is virtually identical. The advantage of
switchis code readability, not speed. In competitions, you can freely choose either. If conditions involve range comparisons (likex > 10), you must useif-else.
Q5: My program produces correct output, but after submission it shows TLE (Time Limit Exceeded). What should I do?
A: Step one: estimate your algorithm's complexity. Look at the range of N β use the "nested loop complexity table" from this chapter to estimate total operations β if it exceeds 10^8, you need to optimize. Common optimization strategies include: reducing the number of loop levels, replacing brute-force search with sorting + binary search (Chapter 3.3), and replacing repeated summation with prefix sums (Chapter 3.2).
π Connections to Later Chapters
- Chapter 2.3 (Functions & Arrays) will let you encapsulate the loop patterns from this chapter into functions, and use arrays to store collections of data
- Chapter 3.2 (Arrays & Prefix Sums) will teach you how to optimize O(NΒ²) range sum queries to O(N) preprocessing + O(1) per query β one of the solutions for when "nested loops are too slow"
- Chapter 3.3 (Sorting & Searching) will teach you binary search, optimizing the O(N) linear search from this chapter to O(log N)
- The five classic loop patterns learned in this chapter (summation, finding max/min, counting, nested iteration, digit processing) are the foundational building blocks for all algorithms in this book
- Nested loop complexity analysis is the first step toward understanding time complexity (a theme throughout the entire book)
Practice Problems
π‘οΈ Warm-Up Problems
Warm-up 2.2.1 β Count to Ten
Print the numbers 1 through 10, each on its own line. Use a for loop.
π‘ Solution (click to reveal)
Approach: A for loop from 1 to 10 (inclusive).
#include <bits/stdc++.h>
using namespace std;
int main() {
for (int i = 1; i <= 10; i++) {
cout << i << "\n";
}
return 0;
}
Key points:
i <= 10(noti < 10) because we want to include 10- Alternatively:
for (int i = 1; i < 11; i++)β same result
Warm-up 2.2.2 β Even Numbers Print all even numbers from 2 to 20, each on its own line.
π‘ Solution (click to reveal)
Approach: Two options β loop by 2s, or loop every number and check if even.
#include <bits/stdc++.h>
using namespace std;
int main() {
// Option 1: step by 2
for (int i = 2; i <= 20; i += 2) {
cout << i << "\n";
}
return 0;
}
Key points:
i += 2increments by 2 each time instead of the usual 1- Alternative:
for (int i = 1; i <= 20; i++) { if (i % 2 == 0) cout << i << "\n"; }
Warm-up 2.2.3 β Sign Check
Read one integer. Print Positive if it's > 0, Negative if it's < 0, Zero if it's 0.
Sample Input: -5 β Output: Negative
π‘ Solution (click to reveal)
Approach: Three-way if/else if/else to cover all cases.
#include <bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
if (n > 0) {
cout << "Positive\n";
} else if (n < 0) {
cout << "Negative\n";
} else {
cout << "Zero\n";
}
return 0;
}
Key points:
- The
elseclause at the end catches exactlyn == 0(since the two conditions above cover n>0 and n<0)
Warm-up 2.2.4 β Multiplication Table of 3 Print the first 10 multiples of 3 (i.e., 3, 6, 9, ..., 30), each on its own line.
π‘ Solution (click to reveal)
Approach: Loop from 1 to 10, print i*3 each time.
#include <bits/stdc++.h>
using namespace std;
int main() {
for (int i = 1; i <= 10; i++) {
cout << i * 3 << "\n";
}
return 0;
}
Key points:
- Alternative:
for (int i = 3; i <= 30; i += 3)β same result
Warm-up 2.2.5 β Sum of Five Read exactly 5 integers (on separate lines or the same line). Print their sum.
Sample Input: 3 7 2 8 5 β Output: 25
π‘ Solution (click to reveal)
Approach: Read 5 times in a loop, accumulate sum.
#include <bits/stdc++.h>
using namespace std;
int main() {
long long sum = 0;
for (int i = 0; i < 5; i++) {
int x;
cin >> x;
sum += x;
}
cout << sum << "\n";
return 0;
}
Key points:
sumshould belong longin case the integers are large- We read exactly 5 times since the problem says "exactly 5 integers"
ποΈ Core Practice Problems
Problem 2.2.6 β FizzBuzz The classic programming challenge: print numbers from 1 to 100. But:
- If the number is divisible by 3, print
Fizzinstead - If divisible by 5, print
Buzzinstead - If divisible by both 3 and 5, print
FizzBuzzinstead
First few lines of output:
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
π‘ Solution (click to reveal)
Approach: Loop 1 to 100. For each number, check divisibility β check the combined case (divisible by both) FIRST, otherwise that case would be caught by the Fizz or Buzz case alone.
#include <bits/stdc++.h>
using namespace std;
int main() {
for (int i = 1; i <= 100; i++) {
if (i % 3 == 0 && i % 5 == 0) {
cout << "FizzBuzz\n";
} else if (i % 3 == 0) {
cout << "Fizz\n";
} else if (i % 5 == 0) {
cout << "Buzz\n";
} else {
cout << i << "\n";
}
}
return 0;
}
Key points:
- Check
i % 3 == 0 && i % 5 == 0FIRST β if you checki % 3 == 0first, then 15 would print "Fizz" and never reach the FizzBuzz case - A number divisible by both 3 and 5 is divisible by 15:
i % 15 == 0also works
Problem 2.2.7 β Minimum of N Read N (1 β€ N β€ 1000), then read N integers. Print the minimum value.
Sample Input:
5
8 3 7 1 9
Sample Output: 1
π‘ Solution (click to reveal)
Approach: Initialize min to the first value read, then update whenever we see something smaller.
#include <bits/stdc++.h>
using namespace std;
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int n;
cin >> n;
int first;
cin >> first;
int minVal = first; // initialize to first element
for (int i = 1; i < n; i++) { // read remaining n-1 elements
int x;
cin >> x;
if (x < minVal) {
minVal = x;
}
}
cout << minVal << "\n";
return 0;
}
Key points:
- Initialize
minValto the first element read (not 0 or INT_MAX), then handle remaining elements in the loop - Alternatively, use
INT_MAXas the initial value:int minVal = INT_MAX;β this is guaranteed to be larger than any int, so the first element will always update it
Problem 2.2.8 β Count Positives Read N (1 β€ N β€ 1000), then read N integers. Print how many of them are strictly positive (> 0).
Sample Input:
6
3 -1 0 5 -2 7
Sample Output: 3
π‘ Solution (click to reveal)
Approach: Maintain a counter, increment when the condition (x > 0) is met.
#include <bits/stdc++.h>
using namespace std;
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int n;
cin >> n;
int count = 0;
for (int i = 0; i < n; i++) {
int x;
cin >> x;
if (x > 0) {
count++;
}
}
cout << count << "\n";
return 0;
}
Key points:
countstarts at 0 and increments only whenx > 0- 0 is NOT positive (not negative either β it's zero), so
x > 0correctly excludes it
Problem 2.2.9 β Star Triangle
Read N. Print a right triangle of * characters with N rows, where row i has i stars.
Sample Input: 4
Sample Output:
*
**
***
****
π‘ Solution (click to reveal)
Approach: Nested loops β outer loop over rows, inner loop prints the right number of stars.
#include <bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
for (int row = 1; row <= n; row++) {
for (int star = 1; star <= row; star++) {
cout << "*";
}
cout << "\n";
}
return 0;
}
Key points:
- Row 1 has 1 star, row 2 has 2 stars, ..., row N has N stars
- The inner loop runs exactly
rowtimes for each value ofrow - Alternative using
string:cout << string(row, '*') << "\n";β creates a string ofrowcopies of*
Problem 2.2.10 β Sum of Digits Read a positive integer N (1 β€ N β€ 10^9). Print the sum of its digits.
Sample Input: 12345 β Sample Output: 15
Sample Input: 9999 β Sample Output: 36
π‘ Solution (click to reveal)
Approach: Use the modulo trick. N % 10 gives the last digit. N / 10 removes the last digit. Repeat until N becomes 0.
#include <bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
int digitSum = 0;
while (n > 0) {
digitSum += n % 10; // add last digit
n /= 10; // remove last digit
}
cout << digitSum << "\n";
return 0;
}
Key points:
n % 10extracts the ones digit (e.g., 12345 % 10 = 5)n /= 10is integer division, removing the last digit (e.g., 12345 / 10 = 1234)- The loop continues until n = 0 (all digits extracted)
- Trace: 12345 β +5 β 1234 β +4 β 123 β +3 β 12 β +2 β 1 β +1 β 0. Sum = 15 β
π Challenge Problems
Challenge 2.2.11 β Collatz Sequence The Collatz sequence starting from N works as follows:
- If N is even: next = N / 2
- If N is odd: next = N * 3 + 1
- Stop when N = 1
Read N. Print the entire sequence (including N and 1). Also print how many steps it takes to reach 1.
Sample Input: 6
Sample Output:
6 3 10 5 16 8 4 2 1
Steps: 8
π‘ Solution (click to reveal)
Approach: Use a while loop. Keep applying the rule until we reach 1. Count steps.
#include <bits/stdc++.h>
using namespace std;
int main() {
long long n;
cin >> n;
int steps = 0;
cout << n; // print starting number
while (n != 1) {
if (n % 2 == 0) {
n = n / 2;
} else {
n = n * 3 + 1;
}
cout << " " << n; // print each next number
steps++;
}
cout << "\n";
cout << "Steps: " << steps << "\n";
return 0;
}
Key points:
- Use
long longβ even starting from small numbers, the sequence can reach large intermediate values (e.g., N=27 reaches 9232!) - The Collatz conjecture says this always reaches 1, but it's not proven for all N
- We print N before the loop (as the starting value), then print each new value after each step
Challenge 2.2.12 β Prime Check
Read N (2 β€ N β€ 10^6). Print prime if N is prime, composite otherwise.
A number is prime if it has no divisors other than 1 and itself.
Sample Input: 17 β Output: prime
Sample Input: 100 β Output: composite
π‘ Solution (click to reveal)
Approach: Trial division β check if any number from 2 to βN divides N. If none do, N is prime. We only need to check up to βN because if N = aΓb and a > βN, then b < βN (so we would have found b already).
#include <bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
bool isPrime = true;
if (n < 2) {
isPrime = false;
} else {
// Check divisors from 2 to sqrt(n)
for (int i = 2; (long long)i * i <= n; i++) {
if (n % i == 0) {
isPrime = false;
break; // found a divisor, no need to continue
}
}
}
cout << (isPrime ? "prime" : "composite") << "\n";
return 0;
}
Key points:
- We check
i * i <= ninstead ofi <= sqrt(n)to avoid floating-point issues (and it's slightly faster) - The
(long long)i * icast prevents overflow when i is large (e.g., i = 1000000, i*i = 10^12) breakexits the loop early as soon as we find any divisor β no need to keep checking- Time complexity: O(βN), so this handles N up to 10^6 easily (β10^6 = 1000 iterations)
Challenge 2.2.13 β Highest Rated Cow Read N (1 β€ N β€ 1000), then read N pairs of (cow name, rating). Find and print the name of the cow with the highest rating.
Sample Input:
4
Bessie 95
Elsie 82
Moo 95
Daisy 88
Sample Output: Bessie
(If there's a tie, print the name of the first one that appeared.)
π‘ Solution (click to reveal)
Approach: Track the best rating and name seen so far. Update whenever we see a strictly higher rating.
#include <bits/stdc++.h>
using namespace std;
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int n;
cin >> n;
string bestName;
int bestRating = -1; // initialize to -1 so any real rating beats it
for (int i = 0; i < n; i++) {
string name;
int rating;
cin >> name >> rating;
if (rating > bestRating) {
bestRating = rating;
bestName = name;
}
}
cout << bestName << "\n";
return 0;
}
Key points:
- Initialize
bestRating = -1(or useINT_MIN) so the first cow always becomes the new best - We use
>(strictly greater), not>=, so in case of a tie, we keep the first one seen (the problem asks for first) - Mixing
cin >> name >> ratingreads a string and then an int from the same line β this works perfectly