#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

int main()
{
    int n;
    cin>>n;
    string temp;
    bool postoji_pustinja = false;
    queue<pair<int, int>> q;
    set<pair<int, int>> visited;
    vector<vector<bool>> more(n, vector<bool>(n));
    vector<vector<int>> toksicnost(n, vector<int>(n));
    vector<vector<ll>> dp(n, vector<ll>(n, numeric_limits<int>::max()));

    vector<vector<int>> najbliza_pustinja(n, vector<int>(n));

    for (int i = 0; i<n; i++) {
            cin>>temp;
        for (int j = 0; j<n; j++) {
            more[i][j] = temp[j] - '0';
            postoji_pustinja = postoji_pustinja || !more[i][j];
            if (!more[i][j]) {
                    q.push({i, j});

            }

        }
    }
    for (int i = 0; i<n; i++) {
        for (int j = 0; j<n; j++) {
            cin>>toksicnost[i][j];
        }
    }

    int k = 0;
    while (!q.empty()) {

        int cur_size = q.size();

        for (int r = 0; r<cur_size; r++) {
            pair<int, int> p = q.front(); q.pop();
            int i = p.first, j = p.second;
            if (visited.count(p) || i<0 || j<0 || i>=n || j>=n) continue;
            najbliza_pustinja[i][j] = k;
            visited.insert({i, j});
            q.push({i+1, j});
            q.push({i-1, j});
            q.push({i, j+1});
            q.push({i, j-1});
        }
        k++;
    }



    /*int cekano = 0;
    dp[0][0] = (!more[0][0]) ? toksicnost[0][0] : 0;
    for (int i = 0; i<n; i++) {
        for (int j = 0; j<n; j++) {
            if (i == j && i == 0) continue;
            int trenutno_potezi = i + j;
            ll up = (i>0) ? dp[i-1][j] : numeric_limits<int>::max();
            ll left = (j>0) ? dp[i][j-1] : numeric_limits<int>::max();
            dp[i][j] = min(up, left);
            if (najbliza_pustinja[i][j] <= trenutno_potezi) {
                dp[i][j] += toksicnost[i][j];
            }
        }
    }*/
    int res = numeric_limits<ll>::max();

    queue<pair<pair<int, int>, pair<int, int>>> q2; // trenutno poteza, da li se prethodno cekalo
    set<pair<pair<int, int>, pair<int, int>>> visited2;
    q2.push({{0, 0}, {0, 0}});

    dp[0][0] = (!more[0][0]) ? toksicnost[0][0] : 0;

    while (!q2.empty()) {

        int cur_size = q2.size();

        for (int r = 0; r<cur_size; r++) {
            pair<pair<int, int>, pair<int, int>> p = q2.front(); q2.pop();
            int i = p.second.first, j = p.second.second;
            int local_k = p.first.first;
            int prethodno_cekanje = p.first.second;
            if (visited2.count(p) || i<0 || j<0 || i>=n || j>=n) continue;

            visited2.insert({{local_k, prethodno_cekanje}, {i, j}});

            if (!(i == 0 && j == 0)) {
                int otrov = (!prethodno_cekanje && local_k >= najbliza_pustinja[i][j]) ? toksicnost[i][j] : 0;
                ll up = (i>0) ? dp[i-1][j] : numeric_limits<int>::max();
                ll left = (j>0) ? dp[i][j-1] : numeric_limits<int>::max();
                dp[i][j] = min(dp[i][j], min(up, left) + otrov);


            }

            if ((i+1 < n && local_k < najbliza_pustinja[i+1][j]) || (j+1 < n && local_k < najbliza_pustinja[i][j+1]))
                q2.push({{local_k+1, 1}, {i, j}});
            if (i+1 < n)
                q2.push({{local_k+1, 0}, {i+1, j}});
            if (j+1 < n)
                q2.push({{local_k+1, 0}, {i, j+1}});

        }
    }





    cout<<dp[n-1][n-1];







}