Problem:
Problem I: Tatami

A tatami mat, a Japanese traditional floor cover, has a rectangular form with aspect ratio 1:2. When
spreading tatami mats on a floor, it is prohibited to make a cross with the border of the tatami mats,
because it is believed to bring bad luck.

Your task is to write a program that reports how many possible ways to spread tatami mats of the same
size on a floor of given height and width.

Input

The input consists of multiple datasets. Each dataset cosists of a line which contains two integers H and W in this order, separated with a single
space. H and W are the height and the width of the floor respectively. The length of the shorter edge of a
tatami mat is regarded as a unit length.

You may assume 0 < H, W ≤ 20.

The last dataset is followed by a line containing two zeros. This line is not a part of any dataset and should not be processed.

Output

For each dataset, print the number of possible ways to spread tatami mats in one line.

Sample Input

3 4
4 4
0 0

Output for the Sample Input

4
2

Solution in C++ (judge verdict: Accepted)

#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <cfloat>
#include <stack>
#include <queue>
#include <vector>
#include <string>
#include <iostream>
#include <set>
#include <map>
#include <time.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


enum Type{
	YOKO,
	TATE,
};


int H,W;
int ans,limit;

bool check(Type type,int row,int col,int table[20][20]){ //新しく角が寄った点だけ調べる

	int start_row,end_row,start_col,end_col;
	if(type == YOKO){
		start_col = max(1,col);
		end_col = min(W-1,col+2);
		start_row = max(1,row);
		end_row = min(H-1,row+1);

	}else{ //type == TATE

		start_col = max(1,col);
		end_col = min(W-1,col+1);
		start_row = max(1,row);
		end_row = min(H-1,row+2);
	}

	for(int row = start_row; row <= end_row; row++){
		for(int col = start_col; col <= end_col; col++){
			if(table[row-1][col-1] == 0 || table[row-1][col] == 0 || table[row][col-1] == 0 || table[row][col] == 0)continue;

			if(table[row-1][col-1] != table[row-1][col] && table[row-1][col-1] != table[row][col-1] && table[row-1][col-1] != table[row][col] &&
				table[row-1][col] != table[row][col-1] && table[row-1][col] != table[row][col] && table[row][col-1] != table[row][col])return false;

		}
	}
	return true;
}

void recursive(int count,int row,int col,int table[20][20]){ //重複計上を防ぐため、行ごとに畳を並べる
	if(row == H){
		if(count == limit+1)ans++;
		return;
	}
	if(col == W){ //次の行へ
		recursive(count,row+1,0,table);
		return;
	}

	if(table[row][col] != 0){ //既に畳が敷いてある(縦)
		if(col <= W-2){
			recursive(count,row,col+1,table);
		}else{ //col == W-1
			recursive(count,row+1,0,table); //次の行へ
		}
		return;
	}

	if(col <= W-2 && table[row][col+1] == 0){ //右に敷ける場合
		int next_table[20][20];
		for(int a = 0; a < H; a++){
			for(int b = 0; b < W; b++)next_table[a][b] = table[a][b];
		}
		next_table[row][col] = count;
		next_table[row][col+1] = count;

		if(check(YOKO,row,col,next_table)){
			recursive(count+1,row,col+2,next_table);
		}
	}
	if(row <= H-2 && table[row+1][col] == 0){ //縦に敷ける場合
		int next_table[20][20];
		for(int a = 0; a < H; a++){
			for(int b = 0; b < W; b++)next_table[a][b] = table[a][b];
		}
		next_table[row][col] = count;
		next_table[row+1][col] = count;

		if(check(TATE,row,col,next_table)){
			recursive(count+1,row,col+1,next_table);
		}

	}

}


int main(){

	int first_table[20][20];

	while(true){
		scanf("%d %d",&H,&W);
		if(H == 0 && W == 0)break;

		if((H*W)%2 == 1){
			printf("0\n");
			continue;
		}

		ans = 0;
		limit = (H*W)/2; //limit枚の畳が敷けるはず

		for(int row = 0; row < H; row++){
			for(int col = 0; col < W; col++){
				first_table[row][col] = 0;
			}
		}
		recursive(1,0,0,first_table);

		printf("%d\n",ans);
	}

	return 0;
}