Minimum Moves to Spread Stones Over Grid
3×3 grid with 9 stones across cells (some empty, some doubled) — backtrack to match donors and receivers by min Manhattan distance.
5 min read
backtracking
Problem#
3×3 grid with 9 total stones (some cells empty, others have ≥1). One move shifts a stone to an adjacent cell. Minimum moves so each cell has exactly 1 stone.
Examples#
grid = [[1,1,0],[1,1,1],[1,2,1]]→3
Constraints#
- Sum of grid values is 9.
Approach#
Collect “donors” (cells with count > 1, with multiplicity = count - 1) and “receivers” (cells with count == 0). Try all assignments of donors to receivers; cost = Manhattan distance per pair. Backtrack over permutations.
Solution#
class Solution {public: int minimumMoves(vector<vector<int>>& grid) { vector<pair<int,int>> donors, receivers; for (int r = 0; r < 3; ++r) for (int c = 0; c < 3; ++c) { if (grid[r][c] > 1) for (int k = 0; k < grid[r][c] - 1; ++k) donors.push_back({r, c}); else if (grid[r][c] == 0) receivers.push_back({r, c}); } sort(donors.begin(), donors.end()); int best = INT_MAX; do { int cost = 0; for (int i = 0; i < (int)donors.size(); ++i) { cost += abs(donors[i].first - receivers[i].first) + abs(donors[i].second - receivers[i].second); } best = min(best, cost); } while (next_permutation(donors.begin(), donors.end())); return best; }};func minimumMoves(grid [][]int) int { type pt struct{ r, c int } var donors, receivers []pt for r := 0; r < 3; r++ { for c := 0; c < 3; c++ { if grid[r][c] > 1 { for k := 0; k < grid[r][c]-1; k++ { donors = append(donors, pt{r, c}) } } else if grid[r][c] == 0 { receivers = append(receivers, pt{r, c}) } } } abs := func(x int) int { if x < 0 { return -x } return x } best := math.MaxInt32 var permute func(i int) permute = func(i int) { if i == len(donors) { cost := 0 for k := 0; k < len(donors); k++ { cost += abs(donors[k].r-receivers[k].r) + abs(donors[k].c-receivers[k].c) } if cost < best { best = cost } return } for j := i; j < len(donors); j++ { donors[i], donors[j] = donors[j], donors[i] permute(i + 1) donors[i], donors[j] = donors[j], donors[i] } } permute(0) return best}from typing import Listfrom itertools import permutations
class Solution: def minimumMoves(self, grid: List[List[int]]) -> int: donors = [] receivers = [] for r in range(3): for c in range(3): if grid[r][c] > 1: for _ in range(grid[r][c] - 1): donors.append((r, c)) elif grid[r][c] == 0: receivers.append((r, c)) best = float('inf') for perm in permutations(donors): cost = 0 for (dr, dc), (rr, rc) in zip(perm, receivers): cost += abs(dr - rr) + abs(dc - rc) if cost < best: best = cost return bestfunction minimumMoves(grid) { const donors = []; const receivers = []; for (let r = 0; r < 3; r++) { for (let c = 0; c < 3; c++) { if (grid[r][c] > 1) { for (let k = 0; k < grid[r][c] - 1; k++) donors.push([r, c]); } else if (grid[r][c] === 0) { receivers.push([r, c]); } } } let best = Infinity; const permute = (i) => { if (i === donors.length) { let cost = 0; for (let k = 0; k < donors.length; k++) { cost += Math.abs(donors[k][0] - receivers[k][0]) + Math.abs(donors[k][1] - receivers[k][1]); } if (cost < best) best = cost; return; } for (let j = i; j < donors.length; j++) { [donors[i], donors[j]] = [donors[j], donors[i]]; permute(i + 1); [donors[i], donors[j]] = [donors[j], donors[i]]; } }; permute(0); return best;}class Solution { private int best; private List<int[]> donors; private List<int[]> receivers;
public int minimumMoves(int[][] grid) { donors = new ArrayList<>(); receivers = new ArrayList<>(); for (int r = 0; r < 3; r++) { for (int c = 0; c < 3; c++) { if (grid[r][c] > 1) { for (int k = 0; k < grid[r][c] - 1; k++) donors.add(new int[]{r, c}); } else if (grid[r][c] == 0) { receivers.add(new int[]{r, c}); } } } best = Integer.MAX_VALUE; permute(0); return best; }
private void permute(int i) { if (i == donors.size()) { int cost = 0; for (int k = 0; k < donors.size(); k++) { int[] d = donors.get(k), r = receivers.get(k); cost += Math.abs(d[0] - r[0]) + Math.abs(d[1] - r[1]); } if (cost < best) best = cost; return; } for (int j = i; j < donors.size(); j++) { Collections.swap(donors, i, j); permute(i + 1); Collections.swap(donors, i, j); } }}function minimumMoves(grid: number[][]): number { const donors: [number, number][] = []; const receivers: [number, number][] = []; for (let r = 0; r < 3; r++) { for (let c = 0; c < 3; c++) { if (grid[r][c] > 1) { for (let k = 0; k < grid[r][c] - 1; k++) donors.push([r, c]); } else if (grid[r][c] === 0) { receivers.push([r, c]); } } } let best = Infinity; const permute = (i: number): void => { if (i === donors.length) { let cost = 0; for (let k = 0; k < donors.length; k++) { cost += Math.abs(donors[k][0] - receivers[k][0]) + Math.abs(donors[k][1] - receivers[k][1]); } if (cost < best) best = cost; return; } for (let j = i; j < donors.length; j++) { [donors[i], donors[j]] = [donors[j], donors[i]]; permute(i + 1); [donors[i], donors[j]] = [donors[j], donors[i]]; } }; permute(0); return best;}Editorial#
3×3 grid bounds donors ≤ 9. next_permutation enumerates all donor orderings; each pairs with the fixed receiver order. Total < 9! = 362880 permutations — easily tractable.
Complexity#
- Time: O(k! × k) where k = #donors ≤ 9.
- Space: O(k).
Concept revision#
Related#