// Original C++ solution (slower):
#pragma GCC optimaze("Ofast")

#include <bits/stdc++.h>

#define all(x) (x).begin(),(x).end()



using namespace std;



const int MSIZE = 16;



int g[MSIZE][MSIZE];

long long Precalc[1 << MSIZE];

vector<int> indexes[1 << MSIZE];

long long dp[1 << MSIZE];



int main() {

    ios_base::sync_with_stdio(false);

    cin.tie(nullptr);

    int n;

    cin >> n;

    for (int i = 0; i < n; i++) {

        for (int j = 0; j < n; j++) {

            cin >> g[i][j];

        }

    }

    for (int mask = 0; mask < (1 << n); mask++) {

        for (int i = 0; i < n; i++) {

            for (int j = i + 1; j < n; j++) {

                if ((mask >> i) & (mask >> j) & 1) {

                    Precalc[mask] += g[i][j];

                }

            }

        }

        for (int i = 0; i < n; i++) {

            if (((mask >> i) & 1) == 0) {

                indexes[mask].push_back(i);

            }

        }

    }



    vector<pair<int,int> > masks(1 << n);

    for (int mask = 0; mask < (1 << n); mask++) {

        masks[mask] = make_pair(__builtin_popcount(mask), mask);

    }

    sort(all(masks));



    for (int i = 0; i < (1 << n); i++) {

        int mask = masks[i].second;

        int sz = indexes[mask].size();

        for (int mask2 = 1; mask2 < (1 << sz); mask2++) {

            int curMask = 0;

            for (int i = 0; i < sz; i++) {

                if ((mask2 >> i) & 1) {

                    curMask |= (1 << indexes[mask][i]);

                }

            }

            dp[mask | curMask] = max(dp[mask] + Precalc[curMask], dp[mask | curMask]);

        }

    }

    cout << dp[(1 << n) - 1] << endl;

}


// Optimized solution to the same problem (faster):
#include <bits/stdc++.h>

#define all(x) (x).begin(),(x).end()



using namespace std;



const int MSIZE = 16;



int g[MSIZE][MSIZE];

long long Precalc[1 << MSIZE];

long long dp[1 << MSIZE];



int main() {

  ios_base::sync_with_stdio(false);

  cin.tie(nullptr);

  int n;

  cin >> n;

  for (int i = 0; i < n; i++) {

    for (int j = 0; j < n; j++) {

      cin >> g[i][j];

    }

  }

  for (int mask = 0; mask < (1 << n); mask++) {

    for (int i = 0; i < n; i++) {

      for (int j = i + 1; j < n && ((mask >> i) & 1); j++) {

        if ((mask >> j) & 1) {

          Precalc[mask] += g[i][j];

        }

      }

    }

  }

  for (int i = 1; i < (1 << n); i++) {

    int mask = i;

    for (int mask2 = mask; mask2 > 0; mask2 = (mask2 - 1) & mask) {

      dp[mask] = max(dp[mask ^ mask2] + Precalc[mask2], dp[mask]);

    }

  }

  cout << dp[(1 << n) - 1] << endl;

}

// Fastest known solution for this problem:
#include <iostream>

#include <algorithm>

#include <vector>

#include <cassert>



using namespace std;





int main() {



  int N;



  cin >> N;

  vector< vector<long long> > A(N, vector<long long>(N));



  for (auto i=0;i <N; i++)

  for (auto j=0;j <N; j++) cin >> A[i][j];



  vector<long long> F( 1<<17, 0);



  // consider all sub sets of {1..N}

  vector<int> l(16, 0);

  for (long long s = 1; s < (1<<N); s++) {

    l.resize(0);



    auto ss= s;

    int c = 0;

    while(ss != 0) {

      if (ss & 1 ) l.push_back(c);

      ss = ss >> 1;

      c++;

    }



    // for (auto tt=0; tt<l.size(); tt++) 

    // cout << "l" << l[tt] << "  ";

    // cout << endl;

    F[s] = 0;

    for (auto i=0; i < l.size(); i++)

    for (auto j=i+1; j < l.size(); j++) F[s] += A[l[i]][l[j]];



    auto L = l.size();



    for (int j = s; j; j = (j-1)&s) {

      F[s] = max( F[s], F[s^j]+F[j]);

    }



    // cout << endl;

  }





  cout << F[ (1<<N)-1] << endl;



  return 0;

}