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



using namespace std;



typedef long long ll;



const int N = 16;



ll dp[1 << N], cost[1 << N], a[N + 1][N + 1];

int n;



vector<int> get_bits(int mask)

{

    vector<int> bits;



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

        if((1 << i) & mask)

            bits.push_back(i);



    return bits;

}



ll solve(int mask)

{

    // cout << "enter: " << mask << endl;



    ll &ans = dp[mask];



    if(ans != -1)

        return ans;



    ans = cost[mask];

    auto bits = get_bits(mask);

    int sz = bits.size();



    for(int submasks = 1; submasks < (1 << sz); submasks++)

    {

        int next = 0;

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

            if((1 << i) & submasks)

                next |= 1 << bits[i];



        ans = max(ans, cost[next] + solve(mask & ~next));

    }



    // cout << mask << " " << ans << endl;



    return ans;

}



int main()

{

    ios_base::sync_with_stdio(false);

    cin.tie(0);

    cout.tie(0);



    memset(dp, -1, sizeof(dp));



    cin >> n;



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

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

            cin >> a[i][j];



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

    {

        auto bits = get_bits(mask);

        int sz = bits.size();



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

            for(int j = i + 1; j < sz; j++)

                cost[mask] += a[bits[i]][bits[j]];

    }



    // cout << "here" << endl;

    // exit(0);



    cout << solve((1 << n) - 1) << endl;



    return 0;

}

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

using namespace std;

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

int n;

long long mem[N], a[17][17], s[N];

bool vis[N];



long long score(int bm) {

	long long ans = 0;

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

		if (!(bm & (1 << i))) continue;

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

			if (!(bm & (1 << j))) continue;

			ans += a[i][j];

		}

	}

	return ans;

}



long long dp(int bm) {

	if (__builtin_popcount(bm) <= 1) {

		return 0;

	}

	if (vis[bm]) {

		return mem[bm];

	}

	vis[bm] = true;



	long long ans = 0;

	for (int fbm = bm; fbm; fbm = (fbm - 1) & bm) {

		long long tans = s[fbm] + dp(bm & ~fbm);

		ans = max(ans, tans);

	}



	return mem[bm] = ans;

}



int main() {

	ios_base::sync_with_stdio(0);

	cin.tie(0);

	

	cin >> n;



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

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

			cin >> a[i][j];

		}

	}



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

		s[i] = score(i);

	}



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



	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;

}