// Template {{{
#include <bits/stdc++.h>
#define REP(i,n) for(int i=0; i<(int)(n); ++i)
using namespace std;
typedef long long LL;

#ifdef LOCAL
#include "contest.h"
#else
#define error(args...) 
#endif

const int dx[4] = {1, 0, -1, 0};
const int dy[4] = {0, 1, 0, -1};
inline bool valid(int x, int w) { return 0 <= x && x < w; }

void iostream_init() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.setf(ios::fixed);
    cout.precision(12);
}
//}}}

const int LEN = 505;
int encode(int N, bool state[3][3]) {
    int s = 0;
    REP(i, N) REP(j, N) {
        s = s << 1 | (state[i][j] ? 1 : 0);
    }
    return s;
}
void decode(int N, int s, bool state[3][3]) {
    for(int i = N-1; i >= 0; i--) {
        for(int j = N-1; j >= 0; j--) {
            state[i][j] = (s & 1);
            s >>= 1;
        }
    }
}
int slow(int N, bool grid[3][3]) {
    assert(N <= 3);
    queue<int> que;
    int dist[1 << 10] = {};
    int start = encode(N, grid);
    memset(dist, -1, sizeof(dist));
    dist[start] = 0;
    que.push(start);
    int ans = -1;
    while(!que.empty()) {
        int s = que.front(); que.pop();
        bool state[3][3];
        decode(N, s, state);
        bool ok = true;
        REP(i, N) REP(j, N) if(!state[i][j]) ok = false;
        if(ok) {
            ans = dist[s];
            break;
        }
        REP(i, N){
            REP(j, N) {
                bool nstate[3][3] = {};
                REP(x, N) REP(y, N) nstate[y][x] = state[y][x];

                bool d[3] = {};
                REP(k, N) d[k] = state[i][k];

                REP(k, N) {
                    nstate[k][j] = d[k];
                }

                int ns = encode(N, nstate);
                if(dist[ns] == -1) {
                    dist[ns] = dist[s] + 1;
                    que.push(ns);
                }
            }
        }
    }
    return ans;
}
int fast(int N, bool grid[LEN][LEN]) {
    bool exist = false;
    REP(y, N) REP(x, N) if(grid[y][x]) exist = true;
    if(!exist) return -1;
    int res = 0;
    int min_cost = INT_MAX;
    REP(y, N) {
        int cost = 1;
        REP(x, N) if(!grid[y][x]) cost++;
        REP(y2, N) if(grid[y2][y]) {
            cost--;
            break;
        }
        REP(x, N) {
            int cnt = 0;
            REP(i, N) if(grid[i][x]) cnt++;
            if(cnt != N || !grid[y][x]) {
                cost++;
            }
        }
        min_cost = min(min_cost, cost);
    }
    res += min_cost;
    return res;
}
// void verify() {
//     for(int n = 1; n <= 3; n++) {
//         REP(s, 1<<(n*n)) {
//             error(n, s);
//             bool g[3][3];
//             decode(n, s, g);
//             bool g2[LEN][LEN] = {};
//             REP(y, n) REP(x, n) g2[y][x] = g[y][x];
//             int st = slow(n, g);
//             error(st);
//             int ft = fast(n, g2);
//             error(ft);
//             if(st != ft) {
//                 error(n, st, ft);
//                 REP(y, n) {
//                     REP(x, n) {
//                         cout << g[y][x] ? "#" : ".";
//                     }
//                     cout << endl;
//                 }
//                 assert(false);
//             }
//         }
//     }
// }
int main(){
    // verify();
    iostream_init();
    int N;
    cin >> N;
    bool grid[LEN][LEN] = {};
    REP(i, N) {
        string s;
        cin >> s;
        REP(j, N) {
            grid[i][j] = s[j] == '#';
        }
    }
    if(N <= 3) {
        bool g[3][3];
        REP(y, N) REP(x, N) g[y][x] = grid[y][x];
        cout << slow(N, g) << endl;
    } else {
        cout << fast(N, grid) << endl;
    }
    return 0;
}



Measured memory_bytes: 512