Problem:
Max Score: $600$ Points

Problem Statement

Sigma and his brother Sugim are in the $H \times W$ grid. They wants to buy some souvenirs.

Their start position is upper-left cell, and the goal position is lower-right cell.

Some cells has a souvenir shop. At $i$-th row and $j$-th column, there is $a_{i, j}$ souvenirs.

In one move, they can go left, right, down, and up cell.

But they have little time, so they can move only $H+W-2$ times.

They wanted to buy souvenirs as many as possible, but they had no computer, so they couldn't get the maximal numbers of souvenirs.

Write a program and calculate the maximum souvenirs they can get, and help them.

Input

The input is given from standard input in the following format.

$H \ W$
$a_{1, 1} \ a_{1, 2} \ \cdots \ a_{1, W}$
$a_{2, 1} \ a_{2, 2} \ \cdots \ a_{2, W}$
$\vdots \ \ \ \ \ \ \ \ \ \ \vdots \ \ \ \ \ \ \ \ \ \ \vdots$
$a_{H, 1} \ a_{H, 2} \ \cdots \ a_{H, W}$

Output

Print the maximum number of souvenirs they can get.

Constraints

$1 \le H, W \le 200$

$0 \le a_{i, j} \le 10^5$

Subtasks

Subtask 1 [ 50 points ]

The testcase in the subtask satisfies $1 \le H \le 2$.

Subtask 2 [ 80 points ]

The testcase in the subtask satisfies $1 \le H \le 3$.

Subtask 3 [ 120 points ]

The testcase in the subtask satisfies $1 \le H, W \le 7$.

Subtask 4 [ 150 points ]

The testcase in the subtask satisfies $1 \le H, W \le 30$.

Subtask 5 [ 200 points ]

There are no additional constraints.

Sample Input 1

3 3
1 0 5
2 2 3
4 2 4

Sample Output 1

21

The cell at $i$-th row and $j$-th column is denoted $(i, j)$.

In this case, one of the optimal solution is this:

Sigma moves $(1, 1) -> (1, 2) -> (1, 3) -> (2, 3) -> (3, 3)$.

Sugim moves $(1, 1) -> (2, 1) -> (3, 1) -> (3, 2) -> (3, 3)$.

Then, they can get $21$ souvernirs.

Sample Input 2

6 6
1 2 3 4 5 6
8 6 9 1 2 0
3 1 4 1 5 9
2 6 5 3 5 8
1 4 1 4 2 1
2 7 1 8 2 8

Sample Output 2

97

Writer : square1001

Solution in C++14 (GCC 5.4.1) (judge verdict: Runtime Error)

#include<bits/stdc++.h>
using namespace std;

typedef pair<int,int> P;
const int INF = (1<<30);
const int MAX = 100000;
const int MAX_V = 50000;
//最小費用流 O(F|E|log|V|) または O(F|V|^2)
struct edge{int to, cap, cost, rev;};

int V;
vector<edge> G[MAX_V];
int h[MAX_V];
int dist[MAX_V];
int prevv[MAX_V],preve[MAX_V];
 
void init(){
  for(int i = 0 ; i < MAX_V ; i++){
    G[i].clear();
  }
}
 
void add_edge(int from,int to,int cap,int cost){
  G[from].push_back((edge){to, cap, cost, (int)G[to].size()});
  G[to].push_back((edge){from, 0, -cost, (int)G[from].size() - 1});
}
 
int min_cost_flow(int s,int t,int f){
  int res = 0;
  fill(h,h+V,0);
  while(f > 0){
    priority_queue<P,vector<P>,greater<P> > que;
    fill(dist,dist + V,INF);
    dist[s] = 0;
    que.push(P(0,s));
    while(!que.empty()){
      P p = que.top(); que.pop();
      int v = p.second;
 
      if(dist[v] < p.first)continue;
      for(int i = 0 ; i < G[v].size() ; i++){
        edge &e = G[v][i];
         
        if(e.cap > 0 && dist[e.to] > dist[v] + e.cost + h[v] - h[e.to]){
          dist[e.to] = dist[v] + e.cost + h[v] - h[e.to];
          prevv[e.to] = v;
          preve[e.to] = i;
          que.push(P(dist[e.to],e.to));
        }
      }
    }
 
    if(dist[t] == INF){
      return -1;
    }
 
    for(int v = 0 ; v < V ; v++) h[v] += dist[v];
       
    int d = f;
 
    for(int v = t; v != s; v = prevv[v]){
      d = min(d,G[prevv[v]][preve[v]].cap);
    }
    f -= d;
    res += d * h[t];
    for(int v = t ; v != s ; v = prevv[v]){
      edge &e = G[prevv[v]][preve[v]];
      e.cap -= d;
      G[v][e.rev].cap += d;
    }
    //cout << res << endl;
  }
  return res;
}

int H,W;
int A[222][222];
int getId(int x,int y){
  return y * W + x;
}
int dx[]={0,1};
int dy[]={1,0};
int main(){
  cin >> H >> W;

  V = H * W * 2;
  int T = H * W;
  init();
  for(int i=0;i<H;i++){
    for(int j=0;j<W;j++){
      cin >> A[j][i];
      for(int k=0;k<2;k++){
        int nx = j+dx[k], ny = i+dy[k];
        if( nx >= W || ny >= H ) continue;
        add_edge( getId(j,i) + T, getId(nx,ny) , INF, 0 );
      }
      add_edge( getId(j,i), getId(j,i)+T, 1, -A[j][i] );
      add_edge( getId(j,i), getId(j,i)+T, INF, 0 );
    }
  }
  /*
  for(int i=0;i<V;i++){
    cout << i << " : " << endl;
    for(edge e : G[i] )
      cout << e.to << " " << e.cap << " " << e.cost << endl;
  }
  */
  //  cout << getId(0,0) << " -> " << getId(W-1,H-1) + T << " = " << V-1 << endl;
  int res = -min_cost_flow( 0, V-1, 2 );
  cout << res << endl;
  
}