#include <bits/stdc++.h>
using namespace std;
struct Cube {
int X, Y, Z;
vector<vector<vector<int>>> a;
};
int nTests;
// Tính số ô 1 còn lại
int countOnes(const Cube &c) {
int cnt = 0;
for (int i = 0; i < c.X; i++)
for (int j = 0; j < c.Y; j++)
for (int k = 0; k < c.Z; k++)
if (c.a[i][j][k] == 1)
cnt++;
return cnt;
}
// Tìm hình chữ nhật toàn 1 lớn nhất trong ma trận 2D (O(n*m))
pair<int, array<int,4>> largestRectangle2D(const vector<vector<int>> &mat) {
int n = mat.size();
if (n == 0) return {0, {0,0,0,0}};
int m = mat[0].size();
vector<int> h(m, 0);
int best = 0;
array<int,4> bestPos = {0,0,0,0};
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++)
h[j] = (mat[i][j] == 0 ? 0 : h[j] + 1);
// tính largest rectangle in histogram
stack<int> st;
int j = 0;
while (j < m) {
if (st.empty() || h[st.top()] <= h[j]) st.push(j++);
else {
int tp = st.top(); st.pop();
int width = st.empty() ? j : j - st.top() - 1;
int area = h[tp] * width;
if (area > best) {
best = area;
bestPos = {i - h[tp] + 1, (st.empty()?0:st.top()+1), i, j-1};
}
}
}
while (!st.empty()) {
int tp = st.top(); st.pop();
int width = st.empty() ? j : j - st.top() - 1;
int area = h[tp] * width;
if (area > best) {
best = area;
bestPos = {i - h[tp] + 1, (st.empty()?0:st.top()+1), i, j-1};
}
}
}
return {best, bestPos};
}
int solveOne(Cube c) {
int cost = 0;
int remaining = countOnes(c);
if (remaining == 0) return 0;
if (remaining == c.X * c.Y * c.Z) return min({c.X, c.Y, c.Z});
while (remaining > 0) {
int bestCount = 0;
int bestAxis = 0; // 0=fix X, 1=fix Y, 2=fix Z
int idx = -1;
array<int,4> rect{0,0,0,0};
// check từng layer fix X
for (int i = 0; i < c.X; i++) {
vector<vector<int>> layer(c.Y, vector<int>(c.Z));
for (int j = 0; j < c.Y; j++)
for (int k = 0; k < c.Z; k++)
layer[j][k] = c.a[i][j][k];
auto [cnt, pos] = largestRectangle2D(layer);
if (cnt > bestCount) {
bestCount = cnt;
bestAxis = 0; idx = i; rect = pos;
}
}
// check từng layer fix Y
for (int j = 0; j < c.Y; j++) {
vector<vector<int>> layer(c.X, vector<int>(c.Z));
for (int i = 0; i < c.X; i++)
for (int k = 0; k < c.Z; k++)
layer[i][k] = c.a[i][j][k];
auto [cnt, pos] = largestRectangle2D(layer);
if (cnt > bestCount) {
bestCount = cnt;
bestAxis = 1; idx = j; rect = pos;
}
}
// check từng layer fix Z
for (int k = 0; k < c.Z; k++) {
vector<vector<int>> layer(c.X, vector<int>(c.Y));
for (int i = 0; i < c.X; i++)
for (int j = 0; j < c.Y; j++)
layer[i][j] = c.a[i][j][k];
auto [cnt, pos] = largestRectangle2D(layer);
if (cnt > bestCount) {
bestCount = cnt;
bestAxis = 2; idx = k; rect = pos;
}
}
if (bestCount == 0) break; // không tìm thấy gì (chỉ còn rải rác)
// Xóa vùng đã chọn (set = 0)
if (bestAxis == 0) { // fix X = idx
for (int j = rect[0]; j <= rect[2]; j++)
for (int k = rect[1]; k <= rect[3]; k++)
if (c.a[idx][j][k]) {
c.a[idx][j][k] = 0;
remaining--;
}
} else if (bestAxis == 1) { // fix Y = idx
for (int i = rect[0]; i <= rect[2]; i++)
for (int k = rect[1]; k <= rect[3]; k++)
if (c.a[i][idx][k]) {
c.a[i][idx][k] = 0;
remaining--;
}
} else { // fix Z = idx
for (int i = rect[0]; i <= rect[2]; i++)
for (int j = rect[1]; j <= rect[3]; j++)
if (c.a[i][j][idx]) {
c.a[i][j][idx] = 0;
remaining--;
}
}
cost++;
}
return cost;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> nTests;
while (nTests--) {
Cube c;
cin >> c.X >> c.Y >> c.Z;
c.a.assign(c.X, vector<vector<int>>(c.Y, vector<int>(c.Z)));
for (int i = 0; i < c.X; i++)
for (int j = 0; j < c.Y; j++) {
string s; cin >> s;
for (int k = 0; k < c.Z; k++)
c.a[i][j][k] = s[k] - '0';
}
cout << solveOne(c) << "\n";
}
return 0;
}