#include using namespace std; struct UnionFind { vector par, rank, size; UnionFind(int n) : par(n), rank(n, 0), size(n, 1) { iota(par.begin(), par.end(), 0); } int find(int i) { return (par[i] == i ? i : (par[i] = find(par[i]))); } bool same(int i, int j) { return find(i) == find(j); } void merge(int i, int j) { if((i = find(i)) == (j = find(j))) return; if(rank[i] > rank[j]) swap(i, j); par[i] = j; size[j] += size[i]; if(rank[i] == rank[j]) rank[j]++; } }; struct E { int u, v, weight; }; int k; vector dna(1010); int cnt(int i, int j) { int ret = 0; for(int l = 0; l < k; ++l) ret += dna[i][l] != dna[j][l]; return ret; } bool operator<(const E &l, const E &r) { return cnt(l.u, l.v) < cnt(r.u, r.v); } int main() { int n; cin >> n >> k; for (int i =0; i < n; i++) cin >> dna[i]; vector edges; edges.reserve(n*(n-1)/2); for(int i = 0; i < n; ++i) for(int j = i+1; j < n; ++j) { edges.push_back({i, j, 0}); } sort(edges.begin(), edges.end()); int cost = 0, count = 0; UnionFind uf(n); for(auto &e : edges) { if(!uf.same(e.u, e.v)) { cost += cnt(e.u, e.v); uf.merge(e.u, e.v); e.v = -e.v; if(++count == n - 1) break; } } cout << cost << '\n'; for(auto e : edges) if(e.v < 0) cout << e.u << ' ' << -e.v << '\n'; return 0; }