#include <bits/stdc++.h>
using namespace std;
using VS = vector<string>;
using LL = long long;
using VI = vector<int>;
using VVI = vector<VI>;
using PII = pair<int, int>;
using PLL = pair<LL, LL>;
using VL = vector<LL>;
using VVL = vector<VL>;
const int INF = 1e9;
const LL LINF = 1e16;
const LL MOD = 1000000007;
const double PI = acos(-1.0);
const long long PD_INF = 1 << 30;
struct Primal_Dual {
  struct edge {
    int to, rev;
    long long cap, cost;
    edge() {}
    edge(int to, long long cap, long long cost, int rev)
        : to(to), cap(cap), cost(cost), rev(rev) {}
  };
  vector<vector<edge>> graph;
  vector<int> prevv, preve;
  vector<long long> potential, min_cost;
  Primal_Dual(int V) : graph(V) {}
  void add_edge(int from, int to, long long cap, long long cost) {
    graph[from].push_back(edge(to, cap, cost, (int)graph[to].size()));
    graph[to].push_back(edge(from, 0, -cost, (int)graph[from].size() - 1));
  }
  long long min_cost_flow(int s, int t, int f) {
    int V = graph.size();
    long long ret = 0;
    priority_queue<pair<long long, int>, vector<pair<long long, int>>,
                   greater<pair<long long, int>>>
        que;
    potential.assign(V, 0);
    preve.assign(V, -1);
    prevv.assign(V, -1);
    for (int(k) = (0); (k) < (V); (k)++) {
      for (int(i) = (0); (i) < (V); (i)++) {
        for (int(j) = (0); (j) < ((int)graph[i].size()); (j)++) {
          edge &e = graph[i][j];
          if (e.cap == 0) continue;
          potential[e.to] = min(potential[e.to], potential[i] + e.cost);
        }
      }
    }
    while (f > 0) {
      min_cost.assign(V, PD_INF);
      que.push(pair<long long, int>(0, s));
      min_cost[s] = 0;
      while (!que.empty()) {
        pair<long long, int> p = que.top();
        que.pop();
        if (min_cost[p.second] < p.first) continue;
        for (int i = 0; i < (int)graph[p.second].size(); i++) {
          edge &e = graph[p.second][i];
          long long nextCost = min_cost[p.second] + e.cost +
                               potential[p.second] - potential[e.to];
          if (e.cap > 0 && min_cost[e.to] > nextCost) {
            min_cost[e.to] = nextCost;
            prevv[e.to] = p.second, preve[e.to] = i;
            que.push(pair<long long, int>(min_cost[e.to], e.to));
          }
        }
      }
      if (min_cost[t] == PD_INF) return -1;
      for (int v = 0; v < V; v++) potential[v] += min_cost[v];
      long long addflow = f;
      for (int v = t; v != s; v = prevv[v]) {
        addflow = min(addflow, graph[prevv[v]][preve[v]].cap);
      }
      f -= addflow;
      ret += addflow * potential[t];
      for (int v = t; v != s; v = prevv[v]) {
        edge &e = graph[prevv[v]][preve[v]];
        e.cap -= addflow;
        graph[v][e.rev].cap += addflow;
      }
    }
    return ret;
  }
};
int main() {
  cin.tie(0);
  ios_base::sync_with_stdio(false);
  int H, W;
  cin >> H >> W;
  vector<vector<LL>> a(H, vector<LL>(W));
  for (int i = 0; i < H; ++i) {
    for (int j = 0; j < W; ++j) {
      cin >> a[i][j];
    }
  }
  auto V = [&](int i, int j, bool OUT) { return 2 * (W * i + j) + OUT; };
  Primal_Dual F(2 * H * W);
  for (int(i) = (0); (i) < (H); (i)++) {
    for (int(j) = (0); (j) < (W); (j)++) {
      F.add_edge(V(i, j, 0), V(i, j, 1), 1, -a[i][j]);
      F.add_edge(V(i, j, 0), V(i, j, 1), 1, 0);
    }
  }
  for (int(i) = (0); (i) < (H - 1); (i)++) {
    for (int(j) = (0); (j) < (W); (j)++) {
      F.add_edge(V(i, j, 1), V(i + 1, j, 0), 2, 0);
    }
  }
  for (int(i) = (0); (i) < (H); (i)++) {
    for (int(j) = (0); (j) < (W - 1); (j)++) {
      F.add_edge(V(i, j, 1), V(i, j + 1, 0), 2, 0);
    }
  }
  LL ans = -F.min_cost_flow(V(0, 0, 0), V(H - 1, W - 1, 1), 2);
  cout << (ans) << "\n";
  return 0;
}
