// Original C++ solution (slower):
#include <bits/stdc++.h>



using namespace std;



typedef long long ll;



const int N = (1 << 16) + 5;

int arr[16][16];

int n;

ll val[N];

vector<int> m[N];



void get_masks(int idx, int mask, int pos)

{

  if(idx == n)

  {

    if(mask)

      m[pos].push_back(mask);

    return;

  }

  get_masks(idx + 1, mask, pos);

  if(mask & (1 << idx))

    get_masks(idx + 1, mask ^ (1 << idx), pos);

}



ll dp[N];



ll solve(int mask)

{

  if(mask == (1 << n) - 1)

    return 0;

  ll &ans = dp[mask];

  if(~ans)

    return ans;

  ans = 0;

  for(auto &x: m[mask])

  {

    ans = max(ans, solve(mask | x) + val[x]);

  }

  return ans;

}

int main()

{

  cin >> n;

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

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

      cin >> arr[i][j];

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

  {

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

    {

      for(int k = j + 1; k < n; k++)

      {

        if((i & (1 << j)) && (i & (1 << k)))

          val[i] += arr[j][k];

      }

    }

  }

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

  {

    int newMask = i;

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

      newMask ^= (1 << j);

    get_masks(0, newMask, i);

  }

  memset(dp, -1, sizeof dp);

  cout << solve(0);

  return 0;

}


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



using namespace std;



typedef long long ll;



const int N = (1 << 16) + 5;

int arr[16][16];

int n;

ll val[N];

vector<int> m[N];

ll dp[N];



void get_masks(int idx, int mask, int pos)

{

  if(idx == n)

  {

    if(mask)

      m[pos].push_back(mask);

    return;

  }

  get_masks(idx + 1, mask, pos);

  if(mask & (1 << idx))

    get_masks(idx + 1, mask ^ (1 << idx), pos);

}



int main()

{

  cin >> n;

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

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

      cin >> arr[i][j];

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

  {

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

    {

      for(int k = j + 1; k < n; k++)

      {

        if((i & (1 << j)) && (i & (1 << k)))

          val[i] += arr[j][k];

      }

    }

  }

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

  {

    int newMask = i;

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

      newMask ^= (1 << j);

    get_masks(0, newMask, i);

  }

  for(int i = (1 << n) - 2; i >= 0; i--)

  {

    for(auto &x: m[i])

    {

      dp[i] = max(dp[i], dp[i | x] + val[x]);

    }

  }

  cout << dp[0];

  return 0;

}


// 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;

}