unittest
{
	assert( [ "3 5" ].parse.expand.solve == 0 );
	assert( [ "4 5" ].parse.expand.solve == 2 );
	assert( [ "5 5" ].parse.expand.solve == 4 );
	assert( [ "100000 2" ].parse.expand.solve == 1 );
	assert( [ "100000 100000" ].parse.expand.solve == 50000 );
}



import std.algorithm;
import std.conv;
import std.range;
import std.stdio;
import std.string;
import std.typecons;

void main()
{
	stdin.byLineCopy.parse.expand.solve.writeln;
}

auto parse( Range )( Range input )
if( isInputRange!Range && is( ElementType!Range == string ) )
{
	auto hw = input.front.split.to!( long[] );
	return tuple( hw[ 0 ], hw[ 1 ] );
}

auto solve( long h, long w )
{
	// 差が小さいほうを取る
	return div3( h, w );
}

auto div3( long h, long w )
{
	if( h % 3 == 0 || w % 3 == 0 ) return 0L;		// マス目に沿って均等に三等分できる
	
	// 三分割したときのサイズを計算
	auto dws = h * ( w / 3 );		// 縦に分割（小さいほう）
	auto dwb = h * ( w / 3 + 1 );		// 縦に分割（大きいほう）
	auto dhs = w * ( h / 3 );		// 横に分割（小さいほう）
	auto dhb = w * ( h / 3 + 1 );		// 横に分割（大きいほう）
	
	// 残りの部分を二等分したときの1つの大きさを計算
	auto rss = new long[ 3 ][ 4 ];
	rss[ 0 ] = dws ~ div2( h, w - w / 3 );
	rss[ 1 ] = dwb ~ div2( h, w - ( w / 3 + 1 ) );
	rss[ 2 ] = dhs ~ div2( h - h / 3, w );
	rss[ 3 ] = dhb ~ div2( h - ( h / 3 + 1 ), w );
	
	// 差が一番小さいものを取る
	auto r = 100000L;
	foreach( rs; rss )
	{
		auto mm = rs.reduce!( max, min );
		r = min( r, mm[ 0 ] - mm[ 1 ] );
	}
	return r;
}

auto div2( long h, long w )
{
	// 二分割したときのサイズを計算
	auto dws = ( 2 <= w ) ? h * ( w / 2 ) : 1000000;		// 縦に分割（小さいほう）
	auto dwb = ( 2 <= w ) ? h * ( w / 2 + 1 ) : 1000000;		// 縦に分割（大きいほう）
	auto dhs = ( 2 <= h ) ? w * ( h / 2 ) : 1000000;		// 横に分割（小さいほう）
	auto dhb = ( 2 <= h ) ? w * ( h / 2 + 1 ) : 1000000;		// 横に分割（大きいほう）
	
	// 偶数行数または偶数列数の場合は等分できる
	if( w % 2 == 0 ) return [ dws, dws ];
	if( h % 2 == 0 ) return [ dhs, dhs ];
	
	// 奇数行数または奇数列数の場合は片方にかたよる
	if( h < w ) return [ dwb, dws ];
	else        return [ dhs, dhb ];
}
