/*
 * Solution by Christian Kauth - July 2010 - Solves all the test cases at http://www.ioi2009.org/downloads/ioi2009_tests.zip
 * This problem can be solved recursively. Memorization is a must then to avoid recomputing several times the same subproblem.
 * As the topic of the seminar was nevertheless dynamic programming, I present a DP implementation of the problem here
 * (don't cut big blocks into smaller ones, but connect small blocks into larger ones)
 * To speed up counting the number of raisins in a given subblock of chocolate, 2-dimnsional prefix-sums are used!
 */

#include <iostream>
using namespace std;

#define MAX_SIZE 51
#define INF 10000000000

int raisins[MAX_SIZE][MAX_SIZE];							// the number of raisins in each piece of chocolate
long long ps[MAX_SIZE][MAX_SIZE];							// the total number of raisins in the pieces of chocolate north-west to the current piece (included) (2-dimensional Prefix Sum)
long long minPay[MAX_SIZE][MAX_SIZE][MAX_SIZE][MAX_SIZE];	// the minimum number of raisins to pay if the subblock defined by the 4 coordinates is split optimally
int N, M;													// the dimensions of the block of chocolate 1..N x 1..M

/*
 * read test case and compute 2D prefix sims
 */
void initialize()
{
	int i,j,rowSum;

	cin>>N>>M;

	for (i=0; i<=M; i++)
		ps[0][i]=0;

	for (i=1; i<=N; i++)
	{
		rowSum=0;
		for (j=1; j<=M; j++)
		{
			cin>>raisins[i][j];
			rowSum += raisins[i][j];
			ps[i][j] = ps[i-1][j] + rowSum;
		}
	}
}

/*
 * computes the optimal solution for small subblocks, which can then be used to solve larger and larger blocks optimally
 */
void dynamic_programming()
{
	// single pieces aren't cut and do not entail any cost
	for (int i=0; i<=N; i++)
		for (int j=0; j<=N; j++)
			for (int k=0; k<=M; k++)
				for (int l=0; l<=M; l++)
					minPay[i][k][j][l] = (i==j && k==l) ? 0 : INF;

	// now we will find the optimal way to connect sub-blocks into bigger and bigger blocks
	for (int height=1; height<=N; height++)
		for (int width=1; width<=M; width++)
			for (int top=1; top+height-1<=N; top++)
				for (int left=1; left+width-1<=M; left++)
				{
					// cost for performing 1 cut/connection in this block
					long long cutCost = ps[top+height-1][left+width-1] - ps[top-1][left+width-1] - ps[top+height-1][left-1] + ps[top-1][left-1];
					// try horizontal connection
					for (int cut=left; cut+1<=left+width-1; cut++)
						minPay[top][left][top+height-1][left+width-1] = min ( minPay[top][left][top+height-1][cut] + minPay[top][cut+1][top+height-1][left+width-1] + cutCost , minPay[top][left][top+height-1][left+width-1] );
					// try vertical connection
					for (int cut=top; cut+1<=top+height-1; cut++)
						minPay[top][left][top+height-1][left+width-1] = min ( minPay[top][left][cut][left+width-1] + minPay[cut+1][left][top+height-1][left+width-1] + cutCost , minPay[top][left][top+height-1][left+width-1] );
				}	
}

int main()
{
	initialize();
	dynamic_programming();
	cout<<minPay[1][1][N][M]<<endl;
	return 0;
}
