/*
* Problem :: 5721 / 사탕 줍기 대회
*
* Kind :: Dynamic Programming
*
* Insight
* - 박스를 고른 칸의
* 위쪽 행, 아래쪽 행,
* 왼쪽 칸, 오른쪽 칸
* 의 사탕이 모두 사라진다
* + 흠... 규칙이 너무 복잡한데...
* 일단 고른 칸에 해당하는 행에서 가져갈 수 있는 사탕의 최대 개수는 알 수 있다
* 행을 기준으로 DP 를 적용하면 되니까
* # 잠깐만! 그럼 각 행에서 가져갈 수 있는 최대 개수를 저장한 배열을 구할 수 있다면
* 그 배열에서 DP 를 또 적용하면 되겠네...?
* -> 왼쪽 칸, 오른쪽 칸 => 행 DP
* 위쪽 행, 아래쪽 행 => 열 DP
* 를 뜻하는 것이었군!!!
*
* Point
* - 1 <= M x N <= 10^5
* 이므로 사탕의 최대개수는 10^8 이 넘지 않아
* int 자료형으로 충분히 계산할 수 있다
* + 1 <= M, N <= 10^5
* 였다면 long 을 써야했겠지
*/
//
// Codeforces
// ver.C++
//
// Created by GGlifer
//
// Open Source
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
#define endl '\n'
// Set up : Global Variables
/* None */
// Set up : Functions Declaration
int DP(vector<int> A);
int main()
{
// Set up : I/O
ios::sync_with_stdio(false);
cin.tie(nullptr);
// Set up : Input
while (true) {
int M, N;
cin >> M >> N;
if (M == 0 && N == 0) break;
vector<int> B[M];
for (int i=0; i<M; i++) {
B[i].resize(N);
for (int j=0; j<N; j++) {
cin >> B[i][j];
}
}
// Process
vector<int> R(M);
for (int i=0; i<M; i++) {
R[i] = DP(B[i]); /* 행 기준 DP */
} int ans = DP(R); /* 열 기준 DP */
// Control : Output
cout << ans << endl;
}
}
// Helper Functions
int DP(vector<int> A)
/* 배열 A 에서 가져갈 수 있는 최대 사탕의 개수를 반환 */
{
int L = A.size();
if (L == 1) return A[0];
int dp[L];
memset(dp, 0, sizeof(dp));
dp[0] = A[0];
dp[1] = max(A[0], A[1]);
for (int i=2; i<L; i++) {
dp[i] = max(dp[i-1], A[i]+dp[i-2]);
}
return dp[L-1];
}