Problem:
Largest Square

Given a matrix (H × W) which contains only 1 and 0, find the area of the largest square matrix which only contains 0s.

Input

H W
c1,1 c1,2 ... c1,W
c2,1 c2,2 ... c2,W
:
cH,1 cH,2 ... cH,W

In the first line, two integers H and W separated by a space character are given. In the following H lines, ci,j, elements of the H × W matrix, are given.

Output

Print the area (the number of 0s) of the largest square.

Constraints

1 ≤ H, W ≤ 1,400

Sample Input

4 5
0 0 1 0 0
1 0 0 0 0
0 0 0 1 0
0 0 0 1 0

Sample Output

4

Solution in C++ (judge verdict: Accepted)

// 最大正方形
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<stack>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<cassert>

#include<vector>
#include<queue>
#include<set>

using namespace std;

const int INF = -1;
const int INV = 0;
const int MAX_H_W = 1400;

// タイルの状態
const int WHITE = 0;
const int BLACK = 1;

// タイル１枚の時の最小正方形
const int MIN_SQUARE = 1;

// タイルの状態を格納する配列
int tile[MAX_H_W][MAX_H_W];

// H : タイルの縦の長さ
// W : タイルの横の長さ
int H, W;

int MaximumSquare(void);

int main(void)
{

	cin >> H >> W;;

	for(int i = 0; i < H; i++)
	{
		for(int j = 0; j < W; j++)
		{
			// タイルの状態を格納
			cin >> tile[i][j];
		}
	}

	printf("%d\n", MaximumSquare());

	return 0;
}

// 最大正方形の問題を解く関数
int MaximumSquare(void)
{
	// 1辺の最大値を格納する変数
	int maxSquareSide = 0;

	// 作成可能な最大正方形の１辺の長さを格納する配列
	int side[MAX_H_W][MAX_H_W];

	// 初期値の代入
	// ( タイルの 1 列目 と 1 行目の状態は最初に調査しておく )
	for(int i = 0; i < W; i++)
	{
		if( tile[0][i] == WHITE )
		{
			// 綺麗なタイル
			side[0][i] = MIN_SQUARE;
			// 最小正方形が１つは出来る
			maxSquareSide = MIN_SQUARE;
		}
		else
		{
			// きたないタイル
			side[0][i] = INV;
		}
	}

	for(int i = 0; i < H; i++)
	{
		if( tile[i][0] == WHITE )
		{
			// 綺麗なタイル
			side[i][0] = MIN_SQUARE;
			// 最小正方形が１つは出来る
			maxSquareSide = MIN_SQUARE;
		}
		else
		{
			// きたないタイル
			side[i][0] = INV;
		}
	}

	int m1, m2;

	for(int i = 1; i < H; i++)
	{
		for(int j = 1; j < W; j++)
		{
			if( tile[i][j] == BLACK )
			{
				// 自分自身が汚いタイルの時は, 正方形は出来ない
				side[i][j] = INV;
				continue;
			}

			if( side[i - 1][j - 1] > MIN_SQUARE && side[i - 1][j] > MIN_SQUARE && side[i][j - 1] > MIN_SQUARE )
			{
				// 自分の位置の左上, 上, 左の要素の中で, 最小の正方形を作る辺を検索する
				// ( 自分の周りの３マス共に正方形が出来ている時 )
				m1 = min(side[i - 1][j - 1], side[i - 1][j]);
				m2 = min(side[i][j - 1], m1);

				// 既に出来ている正方形の辺の長さに＋１する
				side[i][j] = m2 + 1;
			}
			else if( side[i - 1][j - 1] >= MIN_SQUARE && side[i - 1][j] >= MIN_SQUARE && side[i][j - 1] >= MIN_SQUARE )
			{
				// 長さ２の正方形が出来る
				// ( 自分の周りのどこかに正方形が出来ている時 )
				side[i][j] = 2;
			}
			else
			{
				// 周りが汚いタイルに囲まれている時
				// ( 要素１つの正方形となる )
				side[i][j] = MIN_SQUARE;
			}

			if( maxSquareSide < side[i][j] )
			{
				// 最大正方形の１辺の格納
				maxSquareSide = side[i][j];
			}
		}
	}

	// 正方形の面積を返す
	return ( maxSquareSide * maxSquareSide );
}