Number of Ways of Cutting a Pizza

Updated on 10 July, 2025
Number of Ways of Cutting a Pizza header image

Problem Statement

You are provided with a rectangular pizza represented as a matrix of size rows x cols, where each cell of the matrix contains either an 'A' representing an apple or a '.' which is an empty cell. An integer k indicates the number of people among whom the pizza is to be distributed, which also defines the number of cuts (k-1) you can make to divide the pizza. For each cut:

  1. You have to choose the direction of the cut: either vertical or horizontal.
  2. Then you choose a position at the boundary between cells to make the cut, dividing the pizza into two pieces.
  3. A vertical cut distributes the left part, while a horizontal cut distributes the top part of the pizza.

The challenge is to determine all possible ways to cut the pizza so that each piece given to any person contains at least one apple. The result must be returned modulo (10^9 + 7) due to potentially large numbers.

Examples

Example 1

Input:

pizza = ["A..","AAA","..."], k = 3

Output:

3

Explanation:

The figure above shows the three ways to cut the pizza. Note that pieces must contain at least one apple.

Example 2

Input:

pizza = ["A..","AA.","..."], k = 3

Output:

1

Example 3

Input:

pizza = ["A..","A..","..."], k = 1

Output:

1

Constraints

  • 1 <= rows, cols <= 50
  • rows == pizza.length
  • cols == pizza[i].length
  • 1 <= k <= 10
  • pizza consists of characters 'A' and '.' only.

Approach and Intuition

The solution to this problem involves dynamic programming due to the need to compute the number of valid pizza partitions that ensure each part has at least one apple. Here is an intuitive guide through the problem:

  1. Base Calculation:

    • Start by initiating a 3D array dp where dp[i][j][k] represents the number of ways to cut the submatrix from (i, j) to (rows-1, cols-1) into k pieces such that every piece has at least one apple.
  2. Initialization and Base Cases:

    • Set dp[i][j][1] = 1 if the submatrix (i, j) to (rows-1, cols-1) contains at least one apple.
    • Populating this requires a preliminary calculation where you maintain a cumulative sum of apples from bottom right to top left to quickly know if a submatrix has apples.
  3. Recursive Relation:

    • For more than one piece (k > 1), try making either a horizontal or a vertical cut, ensuring there is at least one apple on either side of the cut.
    • The sum of valid ways from the two resulting submatrices after each possible cut gives the value for dp[i][j][k].
  4. Handling Large Numbers:

    • Since the result needs to be modulo (10^9 + 7), take modulo after every addition to prevent overflow and ensure correct results.

By utilizing this systematic approach and carefully partitioning the pizza while maintaining the invariant that each piece has at least one apple, one can determine all valid ways to distribute the pizza.

Solutions

  • C++
cpp
class Solution {
public:
    int countWays(vector<string>& slices, int cuts) {
        int maxRows = slices.size(), maxCols = slices[0].size();
        vector appleCount(maxRows + 1, vector<int>(maxCols + 1));
        vector dp(maxRows, vector<int>(maxCols));
        for (int r = maxRows - 1; r >= 0; r--) {
            for (int c = maxCols - 1; c >= 0; c--) {
                appleCount[r][c] = (slices[r][c] == 'A') + appleCount[r + 1][c] + appleCount[r][c + 1] - appleCount[r + 1][c + 1];
                dp[r][c] = appleCount[r][c] > 0;
            }
        }
        const int modulo = 1000000007;
        for (int remaining = 1; remaining < cuts; remaining++) {
            vector tempDP(maxRows, vector<int>(maxCols));
            for (int r = 0; r < maxRows; r++) {
                for (int c = 0; c < maxCols; c++) {
                    for (int nr = r + 1; nr < maxRows; nr++) {
                        if (appleCount[r][c] - appleCount[nr][c] > 0) {
                            (tempDP[r][c] += dp[nr][c]) %= modulo;
                        }
                    }
                    for (int nc = c + 1; nc < maxCols; nc++) {
                        if (appleCount[r][c] - appleCount[r][nc] > 0) {
                            (tempDP[r][c] += dp[r][nc]) %= modulo;
                        }
                    }
                }
            }
            dp = tempDP;
        }
        return dp[0][0];
    }
};

Explore the solution for calculating the number of ways to cut a pizza into pieces with specified apples (represented by 'A' in the given matrix). The provided C++ code utilizes dynamic programming to address the problem efficiently:

  1. Establish key variables to manage the matrix dimensions (maxRows, maxCols), using the input vector slices that depicts the pizza slices with 'A'. Initialize the appleCount matrix to count the number of apples in submatrices and dp matrix for storing intermediate results.

  2. Populate the appleCount using a reverse loop for matrix dimensions. The value at each position is computed based on the presence of 'A', adjusting counts through neighboring cells to form cumulative counts, avoiding overcounts by subtracting interjected counts.

  3. Initialize dp[0][0] with presence check of apples in the first grid indicating a valid starting slice. If apples are detected, this starting position is set as a potential part of a valid cut.

  4. Set up an additional loop for multiple cut scenarios. Iteratively update the dp array through transient tempDP where for every possible cut, update the ways by considering potential valid horizontal or vertical slices that include apples, ensuring no slice is empty of apples.

  5. Utilize modulo 1000000007 for result calculation to manage large numbers and limit overflow scenarios.

  6. The main computation loop for subsequent cuts processes through potential additional cuts remaining for initial and further decompositions. Check each partition using cumulative apple counts to ensure validity of the partition in retaining at least one apple.

  7. Finalize the module by returning the value dp[0][0] representing ways to partition the entire pizza using permissible cuts, based on specified criteria. The result encapsulates the scenario where all conditions for apple distribution through multiple cuts are met.

This solution approach harnesses dynamic programming to manage complexity, efficiently considering every slice combination through progressive cumulative calculations and updates, thereby ensuring the solution is computationally feasible for larger matrices.

  • Java
java
class Solution {
    public int countWays(String[] slices, int cuts) {
        int m = slices.length, n = slices[0].length();
        int[][] appleCount = new int[m + 1][n + 1];
        int[][] dp = new int[m][n];
        for (int i = m - 1; i >= 0; i--) {
            for (int j = n - 1; j >= 0; j--) {
                appleCount[i][j] = (slices[i].charAt(j) == 'A' ? 1 : 0) + appleCount[i + 1][j] + appleCount[i][j + 1]
                        - appleCount[i + 1][j + 1];
                dp[i][j] = appleCount[i][j] > 0 ? 1 : 0;
            }
        }
        int modulo = (int)1e9 + 7;
        for (int remainingCuts = 1; remainingCuts < cuts; remainingCuts++) {
            int[][] newDp = new int[m][n];
            for (int r = 0; r < m; r++) {
                for (int c = 0; c < n; c++) {
                    for (int rNext = r + 1; rNext < m; rNext++) {
                        if (appleCount[r][c] - appleCount[rNext][c] > 0) {
                            newDp[r][c] += dp[rNext][c];
                            newDp[r][c] %= modulo;
                        }
                    }
                    for (int cNext = c + 1; cNext < n; cNext++) {
                        if (appleCount[r][c] - appleCount[r][cNext] > 0) {
                            newDp[r][c] += dp[r][cNext];
                            newDp[r][c] %= modulo;
                        }
                    }
                }
            }
            dp = Arrays.stream(newDp).map(int[]::clone).toArray(int[][]::new);
        }
        return dp[0][0];
    }
}

To solve the "Number of Ways of Cutting a Pizza" problem, employ dynamic programming in Java as demonstrated in the given code. Address this challenge by first calculating the number of apples in each segment of the pizza and then determining the number of possible ways to make the specified cuts.

Follow this approach:

  1. Build a 2D array appleCount to track the number of apples in every subrectangle extending from each point (i, j) to the bottom right of the grid.

    • A recursive relation combining apple counts from directly below and directly to the right is used, subtracting the count from the diagonal to avoid double counting.
    • Initialize appleCount using the provided 2D slices array.
  2. Use dp array to store ways to cut the pizza when starting from different grid positions, with optimal substructures derived from appleCount.

    • Begin with base values where positions with any apples are set to have one way of making a cut.
  3. Progressively calculate the number of ways to achieve each number of cuts, iterating up to one less than the total cuts to be made.

    • For each position (r, c) in dp, sum potential cuts' contributions from all valid further positions by checking the conditions on apple presence.
    • Utilize modulo arithmetic to keep results within bounds and avoid overflow.
  4. Clone the updates dynamically using Arrays.stream(newDp) which helps in avoiding any interference or side-effects from previously calculated values.

The solution concludes with the element dp[0][0], which holds the total number of ways the pizza can be cut starting from the top left corner following all the constraints.

This approach ensures a comprehensive exploration of all cutting patterns and updates the number of ways dynamically employing past calculations, encapsulated effectively in Java syntax and structure.

  • Python
python
class PizzaSlicer:
    def slice_ways(self, slices: List[str], cut_count: int) -> int:
        row_count = len(slices)
        col_count = len(slices[0])
        apple_presence = [[0] * (col_count + 1) for _ in range(row_count + 1)]
        for i in range(row_count - 1, -1, -1):
            for j in range(col_count - 1, -1, -1):
                apple_presence[i][j] = ((slices[i][j] == 'A')
                                        + apple_presence[i + 1][j]
                                        + apple_presence[i][j + 1]
                                        - apple_presence[i + 1][j + 1])
        dp = [[int(apple_presence[i][j] > 0) for j in range(col_count)]
             for i in range(row_count)]
        MODULO = 1000000007
        for remaining in range(1, cut_count):
            next_dp = [[0 for j in range(col_count)] for i in range(row_count)]
            for i in range(row_count):
                for j in range(col_count):
                    for next_i in range(i + 1, row_count):
                        if apple_presence[i][j] - apple_presence[next_i][j] > 0:
                            next_dp[i][j] += dp[next_i][j]
                    for next_j in range(j + 1, col_count):
                        if apple_presence[i][j] - apple_presence[i][next_j] > 0:
                            next_dp[i][j] += dp[i][next_j]
                    next_dp[i][j] %= MODULO
            dp = next_dp
        return dp[0][0]

The provided Python solution outlines an algorithm implemented in the PizzaSlicer class to count the number of ways a pizza, represented as a grid of characters ('A' for apple and no character for no apple), can be cut into pieces ensuring each piece has at least one apple. The algorithm uses dynamic programming techniques to solve the problem efficiently.

  • The slice_ways method takes slices, which is a list of strings representing the pizza, and cut_count, the number of cuts needed.
  • The initial preprocessing step constructs the apple_presence matrix, which calculates the number of apples present from any given position (i, j) to the bottom right of the grid. This step utilizes memoization to avoid redundant calculations by building upon previously calculated results.
  • A second matrix, dp, is then initialized based on whether the apple is present above and to the left of each position.
  • The main dynamic programming concept applied here involves updating dp with each possible remaining number of cuts. For each cell (i, j), possible cuts along the rows (next_i) and columns (next_j) are considered, and values are propagated forward based on the number of apples segregated by the cut.
  • A modulo operation ensures the result stays within computational limits to avoid overflow and maintain efficiency.
  • Finally, the method returns the total ways to make the required cuts from the top left of the pizza.

This approach guarantees that all possible valid partitions of the pizza are counted, with careful consideration to ensure that each piece of pizza after the cut contains at least one apple. This solution is robust to varying pizza sizes and configurations of apple placements.

Comments

No comments yet.