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;
      }
  }
  