//https://www.luogu.com.cn/problem/P1006
#include<bits/stdc++.h>
#include<unordered_map>
#include<array>
#define ll long long
#define ull unsigned long long
#define all(a) a.begin(),a.end()
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const int N = 2e5 + 5;
/*
将题目转化为同时从左上角传两张纸条到右下角, 使得两条路径不重合, 并且两条路径权值和最大
纸片只能向下或向左传, 所以每次传递会使得纸片的横纵坐标和加一, 若用i表示一张纸片的纵坐标,
用j表示另一张纸片的纵坐标。因为两张纸片的横纵坐标和相同, 则i不等于j就说明两张纸片所处位置不同
*/
int n, m, dp[1055][555][555], a[555][555];//dp第一维表示横纵坐标和, 第二维表示靠左边的纸片纵坐标
//dp第三维表示靠右边的纸片纵坐标
void solve()
{
cin >> n >> m;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
cin >> a[i][j];
for (int k = 2; k < n + m; k++)
{
for (int i = 1; i <= m; i++)
{
for (int j = i + 1; j <= m; j++)
{
dp[k][i][j] = a[k - i][i] + a[k - j][j] + max({dp[k - 1][i][j], dp[k - 1][i - 1][j],
dp[k - 1][i][j - 1], dp[k - 1][i - 1][j - 1] });
}
}
}
cout << dp[n + m - 1][m - 1][m] << '\n';
//因为i < j所以不会dp到右下角, 而要到右下角则只能从其上面或左面的人传过来, 刚好两条路径, 直接输出即可
}
signed main()
{
IOS;
int t = 1;
//cin >> t;
while (t--)
solve();
return 0;
}