#include <bits/stdc++.h>   using namespace std;   template <typename T>   inline bool checkmin(T &a, const T &b) {     return a > b ? a = b, 1 : 0;   }   template <typename T>   inline bool checkmax(T &a, const T &b) {     return a < b ? a = b, 1 : 0;   }   const int MAXN = 2600 / 2;   const int MAXM = 51;   const int MMAX = MAXN * MAXM + MAXN + MAXM + 100;   const int di[] = {0, 0, 1, 0, -1};   const int dj[] = {0, 1, 0, -1, 0};   struct Graph {    public:     int n, m;     int adj[MAXN][MAXM];     void init() {       n = m = 0;       memset(adj, 0, sizeof(adj));     }     void insert(int u, int v) {       n = max(n, v + 1);       m = max(m, v + 1);       adj[u][v] = 1;     }     int find_ans() {       build_dlx();       for (int ans = 0; ans <= n; ++ans) {         if (dfs(0, ans)) {           return ans;         }       }       return -1;     }       private:     int head;     int U[MMAX], D[MMAX], L[MMAX], R[MMAX], CN[MMAX], RN[MMAX];     void addUD(const int &a, const int &h) {       U[a] = h;       D[a] = D[h];       U[D[h]] = a;       D[h] = a;       CN[a] = h;     }     void addLR(const int &a, const int &h) {       L[a] = h;       R[a] = R[h];       L[R[h]] = a;       R[h] = a;       RN[a] = h;     }     void add(const int &k, const int &r, const int &c) {       addUD(k, c);       addLR(k, r);     }     void remove(const int &k) {       for (int j = R[k]; j != k; j = R[j]) {         for (int i = D[j]; i != j; i = D[i]) {           L[R[i]] = L[i];           R[L[i]] = R[i];         }         D[U[j]] = D[j];         U[D[j]] = U[j];       }     }     void unremove(const int &k) {       for (int j = L[k]; j != k; j = L[j]) {         D[U[j]] = j;         U[D[j]] = j;         for (int i = U[j]; i != j; i = U[i]) {           L[R[i]] = i;           R[L[i]] = i;         }       }     }     void build_dlx() {       head = MMAX - 1;       U[head] = D[head] = L[head] = R[head] = head;       int cnt = 0;       for (int i = 0; i < m; i++) {         U[cnt] = D[cnt] = cnt;         addLR(cnt++, head);       }       for (int i = 0; i < n; i++) {         L[cnt] = R[cnt] = cnt;         addUD(cnt++, head);       }       for (int i = 0; i < n; i++) {         for (int j = 0; j < m; j++)           if (adj[i][j]) {             addLR(cnt, m + i);             addUD(cnt, j);             cnt++;           }       }     }     int h() {       int hash[MAXM] = {};       int ans = 0;       for (int c = R[head]; c != head; c = R[c]) {         if (hash[c] == 0) {           hash[c] = 1;           ++ans;           for (int j = D[c]; j != c; j = D[j]) {             for (int i = R[j]; i != j; i = R[i]) {               if (CN[i] != head) {                 hash[CN[i]] = 1;               }             }           }         }       }       return ans;     }     bool dfs(int k, int lim) {       if (k + h() > lim) {         return false;       }       if (R[head] == head) {         return true;       }       int c;       c = R[head];       L[R[c]] = L[c];       R[L[c]] = R[c];       for (int i = D[c]; i != c; i = D[i]) {         L[R[i]] = L[i];         R[L[i]] = R[i];       }       for (int i = D[c]; i != c; i = D[i]) {         remove(RN[i]);         if (dfs(k + 1, lim)) {           return true;         }         unremove(RN[i]);       }       for (int i = U[c]; i != c; i = U[i]) {         L[R[i]] = i;         R[L[i]] = i;       }       L[R[c]] = c;       R[L[c]] = c;       return false;     }   } G;   int N, M;   int change(const int &i, const int &j) { return i * M + j; }   int main() {     while (scanf( %d%d , &N, &M) == 2) {       G.init();       for (int i = 0; i < N; i++) {         for (int j = 0; j < M; j++) {           for (int p = 0; p < 5; p++) {             int ii = i + di[p], jj = j + dj[p];             if (0 <= ii && ii < N && 0 <= jj && jj < M) {               G.insert(change(i, j), change(ii, jj));             }           }         }       }       int res = G.find_ans();       printf( %d n , M * N - res);     }     return 0;   }