source_code: import java.util.*;
  
  public class cf112e {
  	static int n,m,s;
  	static int[][][] memo;
  	public static void main(String[] args) {
  		Scanner in = new Scanner(System.in);
  		n = in.nextInt();
  		m = in.nextInt();
  		if(n > m) {
  			int tmp = n;
  			n = m;
  			m = tmp;
  		}
  		s = (1<<n);
  		memo = new int[s][s][m];
  		for(int i=0; i<s; i++)
  			for(int j=0; j<s; j++)
  				Arrays.fill(memo[i][j], -1);
  		int ret = go(0,0,0);
  		System.out.println(n*m - ret);
  	}
  	static int go(int last, int trans, int r) {
  		if(r==m) {
  			if(trans == 0) return 0;
  			return 100;
  		}
  		if(memo[last][trans][r] != -1) return memo[last][trans][r];
  		int best = 100;
  		for(int crnt = 0; crnt < s; crnt++) {
  			if((trans & ~crnt) != 0) continue; //certain ones have to be here
  			for(int pass = 0; pass < s; pass++) {
  				int tmp = ((1<<n)-1) & ~last;	//move back the ones you can
  				if((pass & ~tmp) != 0) continue; //certain ones have to move on
  				tmp = tmp & ~pass; //find which ones stay
  				boolean fail = false;
  				for(int k=0; k<n; k++) //make sure that the ones that stay
  					if(isSet(tmp,k) && !(isSet(crnt,k-1) || isSet(crnt,k) || isSet(crnt,k+1)))
  						fail = true;
  				if(fail) continue;
  				best = Math.min(best, Integer.bitCount(crnt) + go(crnt,pass,r+1));
  			}
  		}
  		return memo[last][trans][r] = best;
  	}
  	static boolean isSet(int x, int p) {
  		if(p < 0 || p >= n) return false;
  		return (x & (1<<p)) != 0;
  	}
  }
  