#include <iostream>
#include <cstring>
#include <algorithm>
#include <climits>
using namespace std;
const int MAXN = 22;
const int INF = 1e9;
int n;
int original[MAXN][MAXN]; // 原始矩阵
int temp[MAXN][MAXN]; // 临时矩阵,用于模拟翻转
int flip[MAXN][MAXN]; // 记录是否主动翻转
// 判断是否应该翻转当前位置
bool needFlip(int r, int c) {
// 检查当前位置上方格子的状态
// 如果上方格子是1,那么当前位置需要主动翻转
int cnt = temp[r-1][c]; // 上方格子的值
// 加上周围主动翻转的影响
if (c > 1) cnt += flip[r-1][c-1];
if (c < n) cnt += flip[r-1][c+1];
if (r > 1) cnt += flip[r-2][c];
// 奇数个翻转(包括被动翻转)会让值改变
return (cnt % 2 == 1);
}
int solve() {
int minFlips = INF;
// 枚举第一行的所有翻转情况(2^n种可能)
for (int mask = 0; mask < (1 << n); mask++) {
memset(flip, 0, sizeof(flip));
// 复制原始矩阵到临时矩阵
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
temp[i][j] = original[i][j];
}
}
// 设置第一行的翻转
int flips = 0;
for (int j = 1; j <= n; j++) {
if (mask & (1 << (j-1))) {
flip[1][j] = 1;
flips++;
// 应用翻转:自身和四个邻居
temp[1][j] ^= 1;
if (j > 1) temp[1][j-1] ^= 1;
if (j < n) temp[1][j+1] ^= 1;
temp[2][j] ^= 1;
}
}
// 根据上一行的状态决定当前行是否翻转
for (int i = 2; i <= n; i++) {
for (int j = 1; j <= n; j++) {
// 如果上一行的当前位置是1,那么当前行对应位置需要翻转
if (temp[i-1][j] == 1) {
flip[i][j] = 1;
flips++;
// 应用翻转
temp[i][j] ^= 1;
if (j > 1) temp[i][j-1] ^= 1;
if (j < n) temp[i][j+1] ^= 1;
temp[i+1][j] ^= 1;
}
}
}
// 检查最后一行是否全为0
bool allZero = true;
for (int j = 1; j <= n; j++) {
if (temp[n][j] == 1) {
allZero = false;
break;
}
}
if (allZero) {
minFlips = min(minFlips, flips);
}
}
return (minFlips == INF) ? -1 : minFlips;
}
int main() {
cin >> n;
// 读入矩阵
for (int i = 1; i <= n; i++) {
string s;
cin >> s;
for (int j = 1; j <= n; j++) {
original[i][j] = s[j-1] - '0';
}
}
cout << solve() << endl;
return 0;
}