Algorithm (DP on graph)
- Denote the input grid as $\mathcal{G}.$ And the connected components of $\mathcal{G}$ as $\mathcal{C}(\mathcal{G}).$ We use $\mathcal{C}(\mathcal{G})[i]$ to denote the components whose label is $i$.
- Let $g:i\in\mathcal{C}(\mathcal{G})[0]\mapsto\mathbb{Z}$ be the function that computes max area if $v$ is flipped to $1$ after having tried previous previous $i-1$ vertices in $\mathcal{C}(\mathcal{G})[0]$ (we assume that vertiecs in $\mathcal{C}(\mathcal{G})[0]$ has a fixed ordering from $0$ to $\left\lVert \mathcal{C}(\mathcal{G})[0]\right\rVert _{0}-1$; if such ordering does not exists we can manually assign one). $\left\lVert \cdot\right\rVert _{0}$ here denotes that size of the connected components.
- Note that $g$ has the following closed form representation: $$g(i)=\begin{cases}
1+\sum_{u\in\texttt{neighbor}(v),u\notin\mathcal{C}(\mathcal{G})[0]}\left\lVert \mathcal{C}(\mathcal{G})[u]\right\rVert _{0} & \text{if }i=0\\\\
\max\left(g(i-1),1+\sum_{u\in\texttt{neighbor}(v),u\notin\mathcal{C}(\mathcal{G})[0]}\left\lVert \mathcal{C}(\mathcal{G})[u]\right\rVert _{0}\right) & \text{o.w.}
\end{cases}$$
- Then the desired answer is then $g(\left\lVert \mathcal{C}(\mathcal{G})[0]\right\rVert -1).$
- Total time complexity is $O(N^{2})$ since we use DFS to find the connected components and linear scan to evaluate $g$.
Code
struct recursive {
F f;
template <class... Ts>
decltype(auto) operator()(Ts&&... ts) const { return f(std::ref(*this), std::forward<Ts>(ts)...); }
template <class... Ts>
decltype(auto) operator()(Ts&&... ts) { return f(std::ref(*this), std::forward<Ts>(ts)...); }
};
template <class F>
recursive(F)->recursive<F>;
auto const rec = [](auto f) { return recursive{std::move(f)}; };
class Solution {
public:
int largestIsland(vector<vector<int>>& grid) {
struct grid_view_t {
vector<vector<int>> label;
vector<vector<pair<int, int>>> components;
};
const int dr[]{0, 0, 1, -1};
const int dc[]{1, -1, 0, 0};
const int R = size(grid);
const int C = size(grid[0]);
auto inbound = [&](int r, int c) { return r >= 0 and r < R and c >= 0 and c < C; };
const auto grid_view = [&]() {
auto visited = vector<vector<bool>>(R, vector<bool>(C, false));
auto components = vector<vector<pair<int, int>>>{};
auto label = grid;
auto dfs = rec([&](auto&& dfs, int r, int c, auto* container) -> void {
visited[r][c] = true;
container->emplace_back(r, c);
label[r][c] = size(components);
for (int i = 0; i < 4; i++)
if (const auto [nr, nc] = tuple(r + dr[i], c + dc[i]);
inbound(nr, nc) and not visited[nr][nc] and label[nr][nc] == 1)
dfs(nr, nc, container);
});
for (int r = 0; r < R; ++r)
for (int c = 0; c < C; ++c)
if (not visited[r][c] and grid[r][c] == 1)
dfs(r, c, &components.emplace_back());
return grid_view_t{label, components};
}();
const auto& [label_view, components_view] = grid_view;
auto solution = [&] {
int acc = [&](int self = INT_MIN) {
for (const auto& cc : components_view) self = std::max(self, int(size(cc)));
return self;
}();
for (int r = 0; r < R; ++r)
for (int c = 0; c < C; ++c)
if (label_view[r][c] == 0) {
const auto components_involved = [&](unordered_set<int> self = {}) {
for (int i = 0; i < 4; ++i)
if (const auto [nr, nc] = tuple(r + dr[i], c + dc[i]);
inbound(nr, nc) and label_view[nr][nc] != 0)
self.insert(label_view[nr][nc]);
return self;
}();
const auto new_components_size = [&](int acc = 1) {
for (const int cc : components_involved) acc += size(components_view[cc - 1]);
return acc;
}();
acc = std::max(acc, new_components_size);
}
return acc;
}();
return solution;
}
};