Multi-Way Selection
Description
You are given two inputs:
- An integer choice (1 or 2) indicating which geometric shape to compute.
- A list of numeric values that depend on the choice:
- If choice = 1, the list contains a single value R (the radius of a circle).
- If choice = 2, the list contains two values L (length) and B (breadth) of a rectangle.
Your task is to use a switch-case statement to select the correct computation:
- Case 1: Calculate the area of a circle using the formula
- Case 2: Calculate the area of a rectangle using the formula
Return the computed area as a floating-point number.
This problem introduces the switch statement — a multi-way selection construct that allows a program to choose one execution path among many based on the value of a single variable. Unlike if-else if chains that evaluate arbitrary boolean expressions, switch statements compare a single variable against a set of constant values (called cases), making the intent of the code clearer when dealing with discrete choices.
The switch statement is particularly useful when you have a menu-driven program, a state machine, or any situation where a variable can take one of several specific values and each value requires different behavior. Common examples include day-of-week selectors, calculator operations, grade classifiers, and command dispatchers.
Examples
Example 1
Input:
choice = 1, R = 5
Output:
78.53981633974483
Explanation: The choice is 1, so the switch statement matches case 1. We compute the area of a circle with radius 5 using the formula . The value of used is Math.PI (3.141592653589793). After executing the case block, the break statement prevents fall-through to subsequent cases.
Example 2
Input:
choice = 2, L = 5, B = 10
Output:
50.0
Explanation: The choice is 2, so the switch statement matches case 2. We compute the area of a rectangle: . The break statement after this case ensures the default case is not executed.
Example 3
Input:
choice = 3, R = 7
Output:
-1
Explanation: The choice is 3, which does not match any defined case (1 or 2). The switch statement falls through to the default case, which returns -1 to indicate an invalid choice. The default case acts as a safety net — it handles any unexpected input that does not match the defined cases, preventing undefined behavior.
Constraints
- 1 ≤ R, L, B ≤ 100
- choice is a positive integer
- R, L, B are positive integers or floating-point numbers
- Use π = 3.141592653589793 (language-specific constant)
- Return -1 for invalid choice values
Editorial
Brute Force
Intuition
The most straightforward way to handle multiple choices is with a series of independent if statements — one for each possible choice value. We check if the choice equals 1, then separately check if it equals 2, and finally handle the invalid case.
Imagine you are a receptionist at a building with numbered doors. A visitor tells you their door number, and you check your clipboard:
- "Is the door number 1?" Check. If yes, direct them left.
- "Is the door number 2?" Check. If yes, direct them right.
- None matched? Tell them the door doesn't exist.
This approach works, but it evaluates every condition independently. If the visitor says door 1, you still ask about door 2 before concluding. For two doors this is barely noticeable, but imagine a building with 20 floors — you would check all 20 conditions even when the first one matches.
Additionally, using independent if statements does not convey the intent that these choices are mutually exclusive alternatives of a single variable. Someone reading your code might not immediately realize that choice can only match one case at a time.
Step-by-Step Explanation
Let's trace through with choice = 1, R = 5:
Step 1: Read the inputs: choice = 1, and the list contains [5], so R = 5.
Step 2: Evaluate the first condition: choice == 1. Substituting: 1 == 1 → true.
Step 3: Since the condition is true, compute the area of a circle: area = π × R² = 3.14159... × 25 = 78.5398...
Step 4: Store the result. Continue to the next if statement (because these are independent if's).
Step 5: Evaluate the second condition: choice == 2. Substituting: 1 == 2 → false. Skip this block.
Step 6: Check if neither condition matched (for the invalid case). Since condition 1 was true, this check is also wasteful.
Step 7: Return the result: 78.53981633974483.
Now trace with choice = 2, L = 5, B = 10:
Step 8: Evaluate choice == 1: 2 == 1 → false. Skip.
Step 9: Evaluate choice == 2: 2 == 2 → true. Compute area = L × B = 5 × 10 = 50.
Step 10: Return 50.0. Again, all conditions were checked even though only one could match.
Independent If Statements — Checking Every Choice — Watch how independent if statements evaluate every condition sequentially, even after finding the matching choice.
Algorithm
- Read the choice and the corresponding parameters (R for circle, or L and B for rectangle)
- Check if choice == 1 using an independent
ifstatement — if true, compute area = π × R² - Check if choice == 2 using a second independent
ifstatement — if true, compute area = L × B - If neither matched, return -1 for invalid input
- Return the computed area
- All conditions are evaluated independently regardless of prior matches
Code
#include <iostream>
#include <cmath>
using namespace std;
double computeArea(int choice, double arr[], int size) {
double area = -1;
// Independent if statements — all are checked
if (choice == 1) {
double R = arr[0];
area = M_PI * R * R;
}
if (choice == 2) {
double L = arr[0];
double B = arr[1];
area = L * B;
}
return area;
}
int main() {
int choice;
cin >> choice;
if (choice == 1) {
double arr[1];
cin >> arr[0];
cout << computeArea(choice, arr, 1);
}
else if (choice == 2) {
double arr[2];
cin >> arr[0] >> arr[1];
cout << computeArea(choice, arr, 2);
}
else {
cout << -1;
}
return 0;
}import math
def compute_area(choice: int, params: list) -> float:
"""Compute area based on choice using independent if statements."""
area = -1
# Independent if statements — all are checked
if choice == 1:
R = params[0]
area = math.pi * R * R
if choice == 2:
L = params[0]
B = params[1]
area = L * B
return area
choice = int(input())
if choice == 1:
R = float(input())
print(compute_area(choice, [R]))
elif choice == 2:
L, B = map(float, input().split())
print(compute_area(choice, [L, B]))
else:
print(-1)import java.util.Scanner;
public class Solution {
static double computeArea(int choice, double[] arr) {
double area = -1;
// Independent if statements — all are checked
if (choice == 1) {
double R = arr[0];
area = Math.PI * R * R;
}
if (choice == 2) {
double L = arr[0];
double B = arr[1];
area = L * B;
}
return area;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int choice = sc.nextInt();
if (choice == 1) {
double[] arr = { sc.nextDouble() };
System.out.println(computeArea(choice, arr));
} else if (choice == 2) {
double[] arr = { sc.nextDouble(), sc.nextDouble() };
System.out.println(computeArea(choice, arr));
} else {
System.out.println(-1);
}
sc.close();
}
}Complexity Analysis
Time Complexity: O(1)
We perform a fixed number of equality checks (always 2 in this case) and at most one arithmetic computation. All operations are constant-time. However, all conditions are checked regardless of matches.
Space Complexity: O(1)
We use only a few scalar variables (choice, area, R or L and B). No additional data structures are required.
Why This Approach Is Not Efficient
The brute force approach using independent if statements has several drawbacks:
-
Unnecessary checks: With
choice = 1, the program still checkschoice == 2. In a menu with 20 options, 19 checks would be wasted when the first option matches. -
No semantic clarity: Independent if statements do not communicate that these are mutually exclusive alternatives of a single variable. A reader must mentally verify that the conditions are exhaustive and non-overlapping.
-
Potential for bugs: If a programmer accidentally makes two conditions overlap (e.g., using
>=instead of==), multiple blocks could execute, producing incorrect results. Independent if statements do not enforce exclusivity. -
Performance with many cases: For a large number of discrete choices, independent if statements evaluate O(n) conditions in the worst case. A switch statement, depending on the compiler, can use a jump table for O(1) dispatch — the processor jumps directly to the matching case without checking others.
A better approach uses the if-else if-else chain to short-circuit evaluation, and the optimal approach uses the switch-case statement which is purpose-built for selecting among discrete constant values.
Better Approach - If-Else If-Else Chain
Intuition
Instead of checking each choice independently, we link the conditions together using else if. This creates a chain where the program stops evaluating as soon as it finds the first matching condition.
Think of it like a train conductor checking tickets. Instead of asking every passenger "Do you have a ticket for Station 1?", then starting over and asking everyone "Do you have a ticket for Station 2?", a smart conductor asks each passenger one question at a time: "Station 1? No. Station 2? Yes! Here's your stop." — and moves on to the next passenger.
The if-else if-else chain provides:
- Short-circuit evaluation: Once a condition matches, remaining conditions are skipped.
- Mutual exclusivity: The
elsekeyword guarantees only one branch executes. - A default handler: The final
elsecatches any value not explicitly matched.
This is a meaningful improvement over independent if statements, though for discrete value matching, the switch statement (next approach) is even more appropriate.
Step-by-Step Explanation
Let's trace through with choice = 1, R = 5:
Step 1: Read inputs: choice = 1, R = 5.
Step 2: Evaluate the first condition: choice == 1 → 1 == 1 → true.
Step 3: Since the condition is true, compute area = π × 5² = 78.5398. The else-if chain is now done — skip all remaining branches.
Step 4: Return 78.5398. Only 1 comparison was made.
Now trace with choice = 2, L = 5, B = 10:
Step 5: Evaluate choice == 1 → 2 == 1 → false. Move to else-if.
Step 6: Evaluate choice == 2 → 2 == 2 → true. Compute area = 5 × 10 = 50.
Step 7: Return 50.0. Two comparisons were made (worst case for valid inputs).
Now trace with choice = 3 (invalid):
Step 8: Evaluate choice == 1 → false. Move to else-if.
Step 9: Evaluate choice == 2 → false. Fall through to else.
Step 10: The else block returns -1 for invalid choice. No additional comparison needed.
If-Else If-Else Chain — Short-Circuit on Match — Watch how the else-if chain stops at the first matching condition, skipping remaining checks unlike independent if statements.
Algorithm
- Read the choice and corresponding parameters
- If choice == 1, compute area = π × R² and return
- Else if choice == 2 (only checked if Step 2 was false), compute area = L × B and return
- Else (neither matched), return -1 for invalid input
- Maximum 2 comparisons, minimum 1 comparison
Code
#include <iostream>
#include <cmath>
using namespace std;
double computeArea(int choice, double arr[], int size) {
// Linked if-else if-else chain
if (choice == 1) {
double R = arr[0];
return M_PI * R * R;
}
else if (choice == 2) {
double L = arr[0];
double B = arr[1];
return L * B;
}
else {
return -1; // Invalid choice
}
}
int main() {
int choice;
cin >> choice;
if (choice == 1) {
double arr[1];
cin >> arr[0];
cout << computeArea(choice, arr, 1);
}
else if (choice == 2) {
double arr[2];
cin >> arr[0] >> arr[1];
cout << computeArea(choice, arr, 2);
}
else {
cout << -1;
}
return 0;
}import math
def compute_area(choice: int, params: list) -> float:
"""Compute area using if-elif-else chain."""
if choice == 1:
R = params[0]
return math.pi * R * R
elif choice == 2:
L = params[0]
B = params[1]
return L * B
else:
return -1 # Invalid choice
choice = int(input())
if choice == 1:
R = float(input())
print(compute_area(choice, [R]))
elif choice == 2:
L, B = map(float, input().split())
print(compute_area(choice, [L, B]))
else:
print(-1)import java.util.Scanner;
public class Solution {
static double computeArea(int choice, double[] arr) {
// Linked if-else if-else chain
if (choice == 1) {
double R = arr[0];
return Math.PI * R * R;
}
else if (choice == 2) {
double L = arr[0];
double B = arr[1];
return L * B;
}
else {
return -1; // Invalid choice
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int choice = sc.nextInt();
if (choice == 1) {
double[] arr = { sc.nextDouble() };
System.out.println(computeArea(choice, arr));
} else if (choice == 2) {
double[] arr = { sc.nextDouble(), sc.nextDouble() };
System.out.println(computeArea(choice, arr));
} else {
System.out.println(-1);
}
sc.close();
}
}Complexity Analysis
Time Complexity: O(1)
We perform at most 2 comparisons and one arithmetic computation. The else-if chain short-circuits, so best case is 1 comparison (when choice == 1). All arithmetic operations (multiplication, squaring) are constant-time.
Space Complexity: O(1)
Only scalar variables are used. No additional data structures are required.
Why This Approach Is Not Efficient
The if-else if-else chain is functionally correct and more efficient than independent if statements, but it still has limitations when dealing with discrete value matching:
-
Not purpose-built for value matching: The if-else if chain evaluates general boolean expressions. When all you are doing is comparing one variable against a set of constant values, this is overkill. The code reads as a series of arbitrary conditions rather than a structured menu of choices.
-
No jump table optimization: Compilers cannot optimize an if-else if chain into a jump table (a constant-time lookup array of code addresses). With a switch statement, compilers can generate a jump table for contiguous integer cases, achieving O(1) dispatch regardless of the number of cases.
-
Readability at scale: With 10+ choices, an if-else if chain becomes a long vertical list of
else if (choice == X)lines. A switch statement groups all cases under one construct, making it immediately clear that they are alternatives of the same variable. -
Missing the
breakconcept: The switch statement introduces the important concept of fall-through behavior, where omittingbreakcauses execution to continue into the next case. This is both a feature (for grouping cases) and a common bug source — an essential concept for programmers to learn.
The optimal approach uses the switch statement, which is specifically designed for selecting among discrete constant values.
Optimal Approach - Switch-Case Statement
Intuition
The switch statement is a control structure specifically designed for multi-way selection based on the value of a single variable. Instead of writing a chain of if (x == 1) ... else if (x == 2) ..., you write:
switch (x) {
case 1: ... break;
case 2: ... break;
default: ...
}
Think of a switch like a vending machine. You press a button (the switch variable), and the machine uses the button number to jump directly to the correct item slot. It does not check Button 1, then Button 2, then Button 3 in sequence — it has a direct mapping from button to slot. This is how a jump table works at the hardware level.
The switch statement introduces several important programming concepts:
-
Case labels: Each
case X:is a labeled entry point. When the switch variable matches X, execution jumps directly to that label. -
Break statement: After executing a case's code,
breakexits the switch block. Withoutbreak, execution falls through to the next case — this is called fall-through behavior. -
Default case: The
default:label handles any value that does not match any explicit case. It is like theelsein an if-else chain. -
Constant expressions only: Case labels must be compile-time constants (integers or characters). This constraint is what allows the compiler to build a jump table.
For this problem, we switch on choice and have two cases: case 1 computes the circle area, case 2 computes the rectangle area, and the default handles invalid inputs.
Step-by-Step Explanation
Let's trace through with choice = 1, R = 5:
Step 1: Read inputs: choice = 1, R = 5.
Step 2: Enter the switch statement: switch(choice). The switch evaluates the expression choice to get the value 1.
Step 3: The switch mechanism looks for a case label matching the value 1. It finds case 1: and jumps directly to that label — no sequential comparison needed.
Step 4: Execute the code under case 1:. Compute area = π × R² = π × 25 = 78.5398.
Step 5: Hit the break statement. This causes execution to immediately jump out of the entire switch block. The case 2: and default: code are never reached.
Step 6: Return area = 78.5398. Only 1 jump was made (directly to case 1), with no sequential condition checking.
Now trace with choice = 2, L = 5, B = 10:
Step 7: Enter switch(choice) with value 2. Jump directly to case 2:.
Step 8: Compute area = L × B = 5 × 10 = 50. Hit break. Exit the switch block.
Step 9: Return 50.0. Again, a single direct jump — no sequential comparisons.
Now trace with choice = 3 (invalid):
Step 10: Enter switch(choice) with value 3. No case label matches 3. The switch jumps to the default: label. Return -1. The default case is the safety net for unexpected values.
Switch Statement — Direct Jump to Matching Case — Watch how the switch statement jumps directly to the matching case label without sequential condition checking, and how the break statement prevents fall-through.
Algorithm
- Read the choice and corresponding parameters
- Enter the switch statement with
switch(choice) - Case 1: Compute area = π × R². Execute
breakto exit the switch. - Case 2: Compute area = L × B. Execute
breakto exit the switch. - Default: Return -1 for invalid choice.
- Return the computed area
- The switch uses direct dispatch (potentially O(1) via jump table) instead of sequential comparison
Code
#include <iostream>
#include <cmath>
using namespace std;
double computeArea(int choice, double arr[], int size) {
double area;
// Switch statement — direct dispatch to matching case
switch (choice) {
case 1: {
// Circle: area = π × R²
double R = arr[0];
area = M_PI * R * R;
break; // Exit switch — prevents fall-through
}
case 2: {
// Rectangle: area = L × B
double L = arr[0];
double B = arr[1];
area = L * B;
break; // Exit switch
}
default: {
// Invalid choice — no matching case
area = -1;
break;
}
}
return area;
}
int main() {
int choice;
cin >> choice;
if (choice == 1) {
double arr[1];
cin >> arr[0];
cout << computeArea(choice, arr, 1);
}
else if (choice == 2) {
double arr[2];
cin >> arr[0] >> arr[1];
cout << computeArea(choice, arr, 2);
}
else {
cout << -1;
}
return 0;
}import math
def compute_area(choice: int, params: list) -> float:
"""Compute area using Python's match-case statement.
Python 3.10+ introduced 'match-case' as its version of switch.
For earlier versions, use if-elif-else (Python has no switch).
"""
# Python 3.10+ structural pattern matching
match choice:
case 1:
R = params[0]
return math.pi * R * R
case 2:
L = params[0]
B = params[1]
return L * B
case _: # Default case (underscore is the wildcard)
return -1
# Alternative for Python < 3.10 using dictionary dispatch
def compute_area_dict(choice: int, params: list) -> float:
"""Dictionary-based dispatch — Python's idiomatic switch."""
def circle():
return math.pi * params[0] ** 2
def rectangle():
return params[0] * params[1]
operations = {
1: circle,
2: rectangle
}
# .get() with default handles invalid choices
return operations.get(choice, lambda: -1)()
choice = int(input())
if choice == 1:
R = float(input())
print(compute_area(choice, [R]))
elif choice == 2:
L, B = map(float, input().split())
print(compute_area(choice, [L, B]))
else:
print(-1)import java.util.Scanner;
public class Solution {
static double computeArea(int choice, double[] arr) {
double area;
// Switch statement — direct dispatch to matching case
switch (choice) {
case 1:
// Circle: area = π × R²
double R = arr[0];
area = Math.PI * R * R;
break; // Exit switch — prevents fall-through
case 2:
// Rectangle: area = L × B
double L = arr[0];
double B = arr[1];
area = L * B;
break; // Exit switch
default:
// Invalid choice — no matching case
area = -1;
break;
}
return area;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int choice = sc.nextInt();
if (choice == 1) {
double[] arr = { sc.nextDouble() };
System.out.println(computeArea(choice, arr));
} else if (choice == 2) {
double[] arr = { sc.nextDouble(), sc.nextDouble() };
System.out.println(computeArea(choice, arr));
} else {
System.out.println(-1);
}
sc.close();
}
}Complexity Analysis
Time Complexity: O(1)
The switch statement dispatches to the correct case in O(1) time when the compiler generates a jump table. Even without a jump table, the number of operations is constant and minimal. The arithmetic computation (multiplication, π × R²) is also O(1).
Compared to the brute force (always 2 checks) and better approach (1-2 checks), the switch achieves O(1) dispatch regardless of which case matches or how many cases exist. For 2 cases, the practical difference is negligible, but for programs with 10-100 cases, the jump table optimization provides a measurable advantage.
Space Complexity: O(1)
Only scalar variables are used (choice, area, R or L and B). The jump table (if generated by the compiler) is a compile-time artifact stored in the code segment, not in runtime heap or stack memory.