#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
#define MIN(a,b) a>b ? b:a;
#define MAX(a,b) a<b ? b:a;
const int oo = 0x3f3f3f3f;
//문제 : NxN크기의 보드에서, 블록 상태가 주어졌을 때(상황)
// 최대 5번까지 이동시켜서 만들 수 있는 가장 큰 블록의 값을 구하시오.
//동치 : 최대 5번까지 이동시킬 때, 나올 수 있는 모든 경우의 수를 구해서
// 그 중에 제일 큰 블록의 값을 find하기.
//따라서 가능한 모든 경우를 구하되, 조건을 지켜가며 bfs하기. 흠? 이것도 결국 조건인데?
//조건 : 상 하 좌 우로 밀때, 밀리는 곳부터 우선 처리되어야 하며, 한번만 밀려야 함.(즉, 한번 밀린건지, 아닌건지 판별 필요함)
int N;
int board[21][21];
int backup_board[21][21];
int ans=-oo;
int find_max() {
int ret = -oo;
for (int x = 1; x <= N;x++) {
for (int y = 1; y <= N; y++) {
ret = MAX(ret, board[x][y]);
}
}
return ret;
}
//조건 해석하기
void up() {
int temp[21][21] = { 0, };
int canjoin[21][21] = { 0, };//yes가 0 no가 1
for (int y = 1; y <= N;y++) {
int t_idxx = 0;//들어온 원소 수라고 생각 최초는 empthy
for (int x = 1; x <= N;x++) {
if (board[x][y] == 0) continue;
//board[x][y]에 뭔가 있을때..
if (t_idxx == 0) {//처음껀 그냥 옮겨주고
t_idxx++;
temp[t_idxx][y] = board[x][y];
}
else {//나머지의 경우는 같은거 있는지 검사
if (temp[t_idxx][y] == board[x][y] && canjoin[t_idxx][y] == 0) {
temp[t_idxx][y] = temp[t_idxx][y] * 2;
//t_idxx는 그대로 유지
canjoin[t_idxx][y] = 1;
}
else {
t_idxx++;
temp[t_idxx][y] = board[x][y];
}
}
}
}
//마지막으로 복사해주고 끝
for (int x = 1;x <= N;x++) {
for (int y = 1; y <= N; y++) {
board[x][y] = temp[x][y];
}
}
}
void down() {
int temp[21][21] = { 0, };
int canjoin[21][21] = { 0, };//yes가 0 no가 1
for (int y = 1; y <= N;y++) {
int t_idxx = N + 1;//들어온 원소 수라고 생각 최초는 empthy
for (int x = N; x >= 1;x--) {
if (board[x][y] == 0) continue;
//board[x][y]에 뭔가 있을때..
if (t_idxx > N) {//처음껀 그냥 옮겨주고
t_idxx--;
temp[t_idxx][y] = board[x][y];
}
else {//나머지의 경우는 같은거 있는지 검사
if (temp[t_idxx][y] == board[x][y] && canjoin[t_idxx][y] == 0) {
temp[t_idxx][y] = temp[t_idxx][y] * 2;
//t_idxx는 그대로 유지
canjoin[t_idxx][y] = 1;
}
else {
t_idxx--;
temp[t_idxx][y] = board[x][y];
}
}
}
}
//마지막으로 복사해주고 끝
for (int x = 1;x <= N;x++) {
for (int y = 1; y <= N; y++) {
board[x][y] = temp[x][y];
}
}
}
void left() {
int temp[21][21] = { 0, };
int canjoin[21][21] = { 0, };//yes가 0 no가 1
for (int x = 1; x <= N;x++) {
int t_idxx = 0;//들어온 원소 수라고 생각 최초는 empthy
for (int y = 1; y <= N;y++) {
if (board[x][y] == 0) continue;
//board[x][y]에 뭔가 있을때..
if (t_idxx == 0) {//처음껀 그냥 옮겨주고
t_idxx++;
temp[x][t_idxx] = board[x][y];
}
else {//나머지의 경우는 같은거 있는지 검사
if (temp[x][t_idxx] == board[x][y] && canjoin[x][t_idxx] == 0) {
temp[x][t_idxx] = temp[x][t_idxx] * 2;
//t_idxx는 그대로 유지
canjoin[x][t_idxx] = 1;
}
else {
t_idxx++;
temp[x][t_idxx] = board[x][y];
}
}
}
}
//마지막으로 복사해주고 끝
for (int x = 1;x <= N;x++) {
for (int y = 1; y <= N; y++) {
board[x][y] = temp[x][y];
}
}
}
void right() {
int temp[21][21] = { 0, };
int canjoin[21][21] = { 0, };//yes가 0 no가 1
for (int x = 1; x <= N;x++) {
int t_idxx = N + 1;//들어온 원소 수라고 생각 최초는 empthy
for (int y = N; y >= 1; y--) {
if (board[x][y] == 0) continue;
//board[x][y]에 뭔가 있을때..
if (t_idxx > N) {//처음껀 그냥 옮겨주고
t_idxx--;
temp[x][t_idxx] = board[x][y];
}
else {//나머지의 경우는 같은거 있는지 검사
if (temp[x][t_idxx] == board[x][y] && canjoin[x][t_idxx] == 0) {
temp[x][t_idxx] = temp[x][t_idxx] * 2;
//t_idxx는 그대로 유지
canjoin[x][t_idxx] = 1;
}
else {
t_idxx--;
temp[x][t_idxx] = board[x][y];
}
}
}
}
//마지막으로 복사해주고 끝
for (int x = 1;x <= N;x++) {
for (int y = 1; y <= N; y++) {
board[x][y] = temp[x][y];
}
}
}
//동치 분석으로 인한 bfs코드
void dfs(int count)
{
int backup_board[21][21] = {0};
memcpy(backup_board, board, sizeof(board));
if (count == 5) {//재귀의 탈출조건(중요)
int candi = find_max();
ans = MAX(ans, candi);
memcpy(board, backup_board, sizeof(backup_board));
return;
}
for (int i = 1;i <= 4;i++) //1=상, 2=하, 3=좌, 4=우
{
switch (i)
{
case 1:
up();
break;
case 2:
down();
break;
case 3:
left();
break;
case 4:
right();
break;
default:
break;
}
dfs(count + 1);
memcpy(board, backup_board, sizeof(backup_board));
}
}
void print_board( void)
{
for (int x = 1; x <= N; x++)
{
for (int y = 1; y <= N; y++)
{
cout << board[x][y] << ' ';
}
cout << '\n';
}
}
void reset( void)
{
for (int x = 1; x <= N; x++)
{
for (int y = 1; y <= N; y++)
{
board[x][y] = backup_board[x][y];
}
}
}
int main() {
cin >> N;
for (int x = 1; x <= N;x++) {
for (int y = 1; y <= N;y++) {
cin >> board[x][y];
backup_board[x][y] = board[x][y];
}
}
int count = 0;
dfs(count);
cout << ans;
return 0;
}