--{-# LANGUAGE OverloadedStrings #-}
--{-# LANGUAGE OverloadedLists   #-}
{-# LANGUAGE BangPatterns      #-} --引数に!
{-# LANGUAGE MultiWayIf        #-}
{-# LANGUAGE TupleSections     #-}

import Data.Bits
import Data.Maybe (fromJust)
import Data.List
import Data.Array.Unboxed
import Data.Array.MArray
import Data.Array.ST
import qualified Data.ByteString.Lazy.Char8 as B
import qualified Data.Vector.Unboxed as V
import Control.Monad
import Control.Monad.State
import Control.Monad.ST

{-
大きな一つのグループから少しずつ分けていく方針
これ以上得点が大きくならなくなったら終了。
この方法で得点が最大化される理由は以下の通り。
グループの数がnである時の得点を最大化する分け方を行ったとき、その各グループをX_iとラベル付けする。
同様にグループの数がn-1としたとき、各グループをY_iとする。
上記の方法が異なるとしたとき、2つ以上のグループY_j,Y_k,..の部分集合が存在して、それらをすべて含む集合X_jが存在することになる。
特に2つのグループが取れた時を考えれば十分（たぶん）
-}

type Table = UArray (Int,Int) Int
type DP s = STUArray s

eval :: Table -> [Int] -> Int
eval table ls = sub ls
  where sub [] = 0
        sub (x:xs) = (foldl' (\a b -> a + table!(x,b)) 0 xs) + sub xs

evalBit :: Table -> [Int] -> Int -> (Int,([Int],[Int]))
evalBit table set b = let (xs',ys') = partition (testBit b) [0..(length set)-1]
                          xs = map (set!!) xs'
                          ys = map (set!!) ys'
                      in ((eval table xs)+(eval table ys), (xs, ys))

grouping :: Table -> Int -> [Int] -> Int
grouping _ _ [] = 0
grouping table n set = let
    (max0,(set1,set2)) = maximumBy (\x y -> fst x `compare` fst y) $ map (evalBit table set) [0..2^((length set) -1)-1]
    in if set1 == [] || set2 == [] then max0
      else (grouping table n set1) + (grouping table n set2)

solve :: Int -> [Int] -> Int
solve n ls = grouping (listArray ((0,0),(n-1,n-1)) ls) n [0..n-1]

main :: IO ()
main = do
  n <- readLn
  mat <- replicateM n $ map read.words <$> getLine :: IO [[Int]]
  print $ solve n (concat mat)


mod' :: Int -> Int
mod' n = if n < 1000000007 then n else mod n 1000000007
