Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
Program to check how many ways we can choose empty cells of a matrix in python
Suppose we have an N x N binary matrix where 0 represents empty cells and 1 represents blocked cells. We need to find the number of ways to choose N empty cells such that every row and every column has at least one chosen cell. If the answer is very large, return the result mod 10^9 + 7.
Problem Understanding
Given a matrix like this:
We need to select exactly 3 empty cells (one per row and column). The answer is 4 possible configurations.
Solution Approach
We use backtracking with bit manipulation. For each row, we try placing a cell in each available column and use a bitmask to track which columns are already used.
Algorithm Steps
- For each row i, try placing a cell in each empty column j
- Use bitmask to ensure no two cells are in the same column
- Recursively solve for the next row
- Base case: when all rows are processed, return 1
Implementation
class Solution:
def solve(self, matrix):
n = len(matrix)
def backtrack(row, used_cols):
# Base case: all rows processed
if row >= n:
return 1
ways = 0
# Try each column in current row
for col in range(n):
# Check if cell is empty and column not used
if matrix[row][col] == 0 and ((1 << col) & used_cols == 0):
# Choose this cell and recurse
ways += backtrack(row + 1, used_cols | (1 << col))
return ways
return backtrack(0, 0)
# Test with the example
matrix = [
[0, 0, 0],
[0, 0, 0],
[0, 1, 0]
]
solution = Solution()
result = solution.solve(matrix)
print(f"Number of ways: {result}")
Number of ways: 4
How the Algorithm Works
Let's trace through the example:
# Visualize the 4 valid configurations
def print_configurations():
configurations = [
[(0,0), (1,1), (2,2)], # Main diagonal
[(0,0), (1,2), (2,0)], # Anti-pattern 1
[(0,1), (1,0), (2,2)], # Anti-pattern 2
[(0,2), (1,0), (2,0)] # Column 0 heavy
]
for i, config in enumerate(configurations, 1):
print(f"Configuration {i}: {config}")
for row in range(3):
line = ""
for col in range(3):
if (row, col) in config:
line += "X "
elif row == 2 and col == 1: # Blocked cell
line += "# "
else:
line += "0 "
print(line)
print()
print_configurations()
Configuration 1: [(0, 0), (1, 1), (2, 2)] X 0 0 0 X 0 0 # X Configuration 2: [(0, 0), (1, 2), (2, 0)] X 0 0 0 0 X X # 0 Configuration 3: [(0, 1), (1, 0), (2, 2)] 0 X 0 X 0 0 0 # X Configuration 4: [(0, 2), (1, 0), (2, 0)] 0 0 X X 0 0 X # 0
Time and Space Complexity
| Aspect | Complexity | Explanation |
|---|---|---|
| Time | O(N!) | Each row has at most N choices |
| Space | O(N) | Recursion depth |
Conclusion
This backtracking solution efficiently counts valid cell selections using bit manipulation to track used columns. The algorithm ensures exactly one cell per row and column while avoiding blocked cells.
