Skip to main content

Multi-Way Selection

Description

You are given two inputs:

  1. An integer choice (1 or 2) indicating which geometric shape to compute.
  2. 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 A=π×R2A = \pi \times R^2
  • Case 2: Calculate the area of a rectangle using the formula A=L×BA = L \times B

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 π×R2=π×25=78.5398...\pi \times R^2 = \pi \times 25 = 78.5398.... The value of π\pi 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: L×B=5×10=50L \times B = 5 \times 10 = 50. 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 == 1true.

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 == 2false. 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 == 1false. Skip.

Step 9: Evaluate choice == 2: 2 == 2true. 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

  1. Read the choice and the corresponding parameters (R for circle, or L and B for rectangle)
  2. Check if choice == 1 using an independent if statement — if true, compute area = π × R²
  3. Check if choice == 2 using a second independent if statement — if true, compute area = L × B
  4. If neither matched, return -1 for invalid input
  5. Return the computed area
  6. 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:

  1. Unnecessary checks: With choice = 1, the program still checks choice == 2. In a menu with 20 options, 19 checks would be wasted when the first option matches.

  2. 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.

  3. 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.

  4. 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 else keyword guarantees only one branch executes.
  • A default handler: The final else catches 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 == 11 == 1true.

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 == 12 == 1false. Move to else-if.

Step 6: Evaluate choice == 22 == 2true. 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 == 1false. Move to else-if.

Step 9: Evaluate choice == 2false. 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

  1. Read the choice and corresponding parameters
  2. If choice == 1, compute area = π × R² and return
  3. Else if choice == 2 (only checked if Step 2 was false), compute area = L × B and return
  4. Else (neither matched), return -1 for invalid input
  5. 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:

  1. 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.

  2. 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.

  3. 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.

  4. Missing the break concept: The switch statement introduces the important concept of fall-through behavior, where omitting break causes 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:

  1. Case labels: Each case X: is a labeled entry point. When the switch variable matches X, execution jumps directly to that label.

  2. Break statement: After executing a case's code, break exits the switch block. Without break, execution falls through to the next case — this is called fall-through behavior.

  3. Default case: The default: label handles any value that does not match any explicit case. It is like the else in an if-else chain.

  4. 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

  1. Read the choice and corresponding parameters
  2. Enter the switch statement with switch(choice)
  3. Case 1: Compute area = π × R². Execute break to exit the switch.
  4. Case 2: Compute area = L × B. Execute break to exit the switch.
  5. Default: Return -1 for invalid choice.
  6. Return the computed area
  7. 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.