#include using namespace std; static constexpr int MAXN = 50; static constexpr int MAXV = MAXN * MAXN; static constexpr int SAMPLES = 250; int N, K; vector d; bool dry[SAMPLES][MAXV]; bool cutCell[MAXV]; int ord_[MAXV]; int low_[MAXV]; int sub_[MAXV]; int parent_[MAXV]; int sepSize_[MAXV]; long long sepSq_[MAXV]; long long totalValue[MAXV]; int timer_; void dfs(int v, int s, vector& comp) { ord_[v] = low_[v] = timer_++; sub_[v] = 1; comp.push_back(v); int r = v / N; int c = v % N; static const int dr[4] = {-1, 1, 0, 0}; static const int dc[4] = {0, 0, -1, 1}; for (int dir = 0; dir < 4; ++dir) { int nr = r + dr[dir]; int nc = c + dc[dir]; if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue; int to = nr * N + nc; if (cutCell[to]) continue; if (!dry[s][to]) continue; if (ord_[to] == -1) { parent_[to] = v; dfs(to, s, comp); sub_[v] += sub_[to]; low_[v] = min(low_[v], low_[to]); if (low_[to] >= ord_[v]) { sepSize_[v] += sub_[to]; sepSq_[v] += 1LL * sub_[to] * sub_[to]; } } else if (to != parent_[v]) { low_[v] = min(low_[v], ord_[to]); } } } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cin >> N >> K; d.resize(N); for (int i = 0; i < N; ++i) cin >> d[i]; int V = N * N; vector trees; trees.reserve(V); for (int r = 0; r < N; ++r) { for (int c = 0; c < N; ++c) { if (d[r][c] != '0') { trees.push_back(r * N + c); } } } mt19937 rng(123456789); for (int v = 0; v < V; ++v) { int r = v / N; int c = v % N; int p = d[r][c] - '0'; for (int s = 0; s < SAMPLES; ++s) { dry[s][v] = false; } if (p == 0) continue; array order; iota(order.begin(), order.end(), 0); shuffle(order.begin(), order.end(), rng); int cnt = p * 25; for (int k = 0; k < cnt; ++k) { dry[order[k]][v] = true; } } vector answer; answer.reserve(K); for (int step = 0; step < K; ++step) { fill(totalValue, totalValue + V, 0LL); for (int s = 0; s < SAMPLES; ++s) { fill(ord_, ord_ + V, -1); fill(parent_, parent_ + V, -1); fill(sepSize_, sepSize_ + V, 0); fill(sepSq_, sepSq_ + V, 0LL); timer_ = 0; for (int start : trees) { if (cutCell[start]) continue; if (!dry[s][start]) continue; if (ord_[start] != -1) continue; vector comp; comp.reserve(256); dfs(start, s, comp); int S = static_cast(comp.size()); long long before = 1LL * S * S; for (int v : comp) { int remain = S - 1 - sepSize_[v]; long long after = sepSq_[v] + 1LL * remain * remain; totalValue[v] += before - after; } } } int best = -1; for (int v : trees) { if (cutCell[v]) continue; if (best == -1) { best = v; continue; } if (totalValue[v] != totalValue[best]) { if (totalValue[v] > totalValue[best]) { best = v; } continue; } int vr = v / N; int vc = v % N; int br = best / N; int bc = best % N; int vd = d[vr][vc] - '0'; int bd = d[br][bc] - '0'; if (vd != bd) { if (vd > bd) best = v; continue; } if (vr != br) { if (vr < br) best = v; continue; } if (vc < bc) best = v; } if (best == -1) break; cutCell[best] = true; answer.push_back(best); } cout << answer.size() << '\n'; for (int v : answer) { cout << v / N << ' ' << v % N << '\n'; } return 0; }