#include <bits/stdc++.h>
using namespace std;
/*
QUESTION IN SIMPLE WORDS
------------------------
Grid contains:
- 2 = start
- 3 = finish
- 1 = special cell, must visit at least one
- 4 = blocked
- others = normal usable cells
You may revisit cells.
But cost is counted only the FIRST time a cell is used.
So the real goal is:
Find a valid walk from 2 to 3 that touches at least one 1
while using the minimum number of distinct cells.
------------------------------------------------------------
BRUTE FORCE IDEA
------------------------------------------------------------
Try all possible walks from start to finish.
Keep only those that:
- reach 3
- touch at least one 1
For each walk, count how many distinct cells were used.
------------------------------------------------------------
WHY BRUTE FORCE IS TOO SLOW
------------------------------------------------------------
The number of possible walks is huge.
Even a small grid can have too many possibilities.
------------------------------------------------------------
OPTIMIZED IDEA
------------------------------------------------------------
Convert every usable cell into a graph node.
We need a connected structure that covers:
- start
- finish
- at least one '1'
We use a small DP on bitmasks:
1 -> start is covered
2 -> finish is covered
4 -> some '1' is covered
So mask = 7 means all requirements are satisfied.
dp[mask][v] =
minimum number of distinct cells needed for a connected structure
ending at node v and already covering the things in mask
*/
int minDistinctCells(vector<vector<int>> grid) {
int n = grid.size();
int m = grid[0].size();
vector<vector<int>> id(n, vector<int>(m, -1));
vector<pair<int, int>> cells;
int start = -1, finish = -1;
vector<int> ones;
// Give each usable cell a graph node id
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (grid[i][j] == 4) continue;
id[i][j] = (int)cells.size();
cells.push_back({i, j});
}
}
int V = (int)cells.size();
if (V == 0) return -1;
vector<vector<int>> adj(V);
int dx[4] = {-1, 1, 0, 0};
int dy[4] = {0, 0, -1, 1};
// Build graph edges for 4-direction movement
for (int v = 0; v < V; v++) {
auto [x, y] = cells[v];
if (grid[x][y] == 2) start = v;
if (grid[x][y] == 3) finish = v;
if (grid[x][y] == 1) ones.push_back(v);
for (int dir = 0; dir < 4; dir++) {
int nx = x + dx[dir];
int ny = y + dy[dir];
if (nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
if (id[nx][ny] == -1) continue;
adj[v].push_back(id[nx][ny]);
}
}
if (start == -1 || finish == -1 || ones.empty()) return -1;
const int INF = 1e9;
vector<vector<int>> dp(8, vector<int>(V, INF));
// Base states
dp[1][start] = 1;
dp[2][finish] = 1;
for (int v : ones) dp[4][v] = 1;
for (int mask = 1; mask < 8; mask++) {
// Merge smaller masks at the same ending node
for (int sub = (mask - 1) & mask; sub; sub = (sub - 1) & mask) {
int other = mask ^ sub;
if (sub > other) continue;
for (int v = 0; v < V; v++) {
if (dp[sub][v] == INF || dp[other][v] == INF) continue;
// -1 because node v was counted twice
dp[mask][v] = min(dp[mask][v], dp[sub][v] + dp[other][v] - 1);
}
}
// Spread this state through the graph
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
for (int v = 0; v < V; v++) {
if (dp[mask][v] < INF) pq.push({dp[mask][v], v});
}
while (!pq.empty()) {
auto [dist, u] = pq.top();
pq.pop();
if (dist != dp[mask][u]) continue;
for (int v : adj[u]) {
if (dp[mask][v] > dp[mask][u] + 1) {
dp[mask][v] = dp[mask][u] + 1;
pq.push({dp[mask][v], v});
}
}
}
}
int ans = INF;
for (int v = 0; v < V; v++) {
ans = min(ans, dp[7][v]);
}
return ans == INF ? -1 : ans;
}
int main() {
vector<vector<int>> grid = {
{2, 0, 1},
{0, 4, 0},
{0, 0, 3}
};
cout << minDistinctCells(grid) << '\n';
return 0;
}