You are given a rectangular board of *M* × *N* squares. Also you are given an unlimited number of standard domino pieces of 2 × 1 squares. You are allowed to rotate the pieces. You are asked to place as many dominoes as possible on the board so as to meet the following conditions:

1. Each domino completely covers two squares.

2. No two dominoes overlap.

3. Each domino lies entirely inside the board. It is allowed to touch the edges of the board.

Find the maximum number of dominoes, which can be placed under these restrictions.
In a single line you are given two integers *M* and *N* — board sizes in squares (1 ≤ *M* ≤ *N* ≤ 16).
from collections import defaultdict
from tkinter import N

# n=int(input())
# c=0
# for _ in range(n):
#     l=list(map(int,input().split()))
#     o=0
#     for i in l:
#         if(i==1):
#             o+=1
#     if(o>1):
#         c+=1
# print(c)
# def firstRepeated(arr, n): 
#     d=defaultdict(list)
#     for i in range(len(arr)):

#         d[arr[i]].append(i)
#     for i,j in d.items():
#         if(len(j)>1):
#             return j[0]
        
# arr=[1,2,5,3,4,9,3,5]
# n=len(arr)
# print(firstRepeated(arr,n))

# a=1
# b=4
# c=a^b
# a=c^a
# b=c^b
# print(a,b)
# import bisect
# a=[1,1,5,5,5,6,4,4,4,4]
# k=5
# # print(bisect.bisect_left(a,8))

# # Python3 program to implement
# # the above approach

# # Function to get
# # the closest value
# import math
# def clostVal(arr, N, k):
#     arr.sort()
#     j=arr.index(k)
#     for i in range(j+1,N):
#         if(k+arr[i]):
#             aux=math.floor((k+arr[i])/2)
#             if(aux in arr):
#                 continue
#             else:
#                 return aux
            


# arr=[ 1,2,3,4,5,6]
# K = 6
# N = len(arr)
# print(clostVal(arr, N, K))

# n=13
# v=0
# i=2
# mask=~(1<<i)
# cl=n&mask
# print((v<<i))
# n=cl|(v<<i)
# print(n)

# # n=13
# # print(bin(13))
# # mask=(-1<<2)
# # print(mask,bin(mask))
# # n=n&mask
# # print(n,bin(n))

# t =input()
# k=int(input())

# class Pair:
#     def __init__(self, c, ctr):
#         self.c = c
#         self.ctr = ctr
# class Solution:
#     def reduced_String(self, k, s):
#         if (k == 1):
#             return "" 
#         st = []
#         for i in range(len(s)):
#             if (len(st) == 0):
#                 st.append((Pair(s[i], 1)))
#                 continue
#             if (st[-1].c == s[i]):
#                 pair = st.pop()
#                 pair.ctr += 1
#                 if (pair.ctr == k):
#                     continue
#                 else:
#                     st.append(pair)
#             else:
#                 st.append((Pair(s[i], 1)))
#             ans = ""
#         while (len(st) > 0):
#             c = st[-1].c
#             cnt = st[-1].ctr
#             while (cnt > 0):
#                 ans = c + ans
#                 cnt -= 1
#             st.pop()
#         return (ans)

# obj = Solution()
# print(obj.reduced_String(k, t))
# def cnt(n):
#     return (n * (n + 1)) // 2
# def solve(A):
#     MOD = int(1e9 + 7)
#     ans = 0
#     n = len(A)
#     for b in range(27):
#         c = 0
#         C = cnt(n)
    
#         for i in range(n):
#             if A[i] & 1:
#                 print(b,i,A[i])
#                 C -= cnt(c)
#                 c = 0
#             else:
#                 c += 1
#             A[i] >>= 1
#         C -= cnt(c)
#         ans = (ans + (1 << b) * C) % MOD
#     return ans
# A=[1,2,3,4]
# print(solve(A))



# ans = []
# curr = []
# def solve(i, n, A):
#     global ans,curr
#     if i == n:
#         ans.append(sorted(curr.copy()))
#         return
#     solve(i+1,n,A)
#     curr.append(A[i])
#     solve(i+1,n,A)
#     curr.pop()
# def subsets(A):
#     global ans,curr
#     ans = []
#     n = len(A)
#     solve(0, n, A)
#     return sorted(ans)
# su=[4,1,7]
# print(subsets(su))
# for _ in range(int(input())):
#     ma="Timur"
#     met=len(ma)
#     n=int(input())
#     s=input()
#     for i in range(len(s)):
#         if(s[i] in ma):
#             idx=ma.index(s[i])
#             ma=ma[:idx]+ma[idx+1:]
#     if(ma=="" and i==met-1):
#         print("Yes")
#     else:
#         print("No")

# for _ in range(int(input())):
#     n=int(input())
#     s1=input()
#     s2=input()
#     aux=["G","B"]
#     i=0
#     flag="Yes"
#     j=0
#     while(i<len(s1) and j<len(s2)):
#         if(s1[i] in aux and s2[j] in aux):
#             i+=1
#             j+=1
#         elif(s1[i]=="R" and s2[j]=="R"):
#             i+=1
#             j+=1
#         else:
#             flag="No"
#             break
#     print(flag)

# RGBRRGBR
# RGGRRBGR

# for _ in range(int(input())):
#     n=int(input())
#     a=input()
#     b=input()
#     c=input()
# a=a.split()
# b=b.split()
# c=c.split()
# d=defaultdict(lambda:1)
# for i in range(n):
#     if(a[i] in b):
#         if(a[i] in d):
#             d[a[i]]+=1
#         else:
#             d[a[i]]=2
#     if(a[i] in c):
#         if(a[i] in d):
#             d[a[i]]+=1
#         else:
#             d[a[i]]=2
#     else:
#         d[a[i]]=1
# print(d)
        

# orz for qaq
# qaq orz for
# cod for ces

# m,n=map(int,input().split())
# l=list(map(int,input().split()))
# c=0
# for i in l:
#     if(i>=l[n-1] and i>0):
#         c+=1
# print(c)
# num=31
# print(num.bit_length())
# a, b  = map(int, input().split())
 
# k = 2**(a^b).bit_length()
# print(k-1)

# l,r=tuple(map(int,input().split(" ")))
# x=l^r
# pow=1
# while(pow<=x) :
#     pow*=2
    
# print(pow-1)

# class Node:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
# def dfs(root, maxsofar):
#     if root == None:
#         return 0
#     ans = 0
#     if root.val > maxsofar:
#         ans = 1
#         maxsofar = root.val
#     ans = ans + dfs(root.left, maxsofar)
#     ans = ans + dfs(root.right, maxsofar)
#     return ans

# def solve(A):
#     return dfs(A, 0)
# root = Node(4)
# root.left = Node(5)
# root.right = Node(2)
# root.right.left=Node(3)
# root.right.right=Node(6)
# actual = solve(root)
# print(actual)
# print(bin(100))
# n=32
# c=0
# while(n):
#     c+=n&1
#     n=n>>1
# print(c)
# 3>>1
# 3/2**1
# a>>i = a/2**i
# 1 1 0 0 1
#   1 1 0 0 
  
# a<<i= a*2**i
#     1 1 0 0 1
#   1 1 0 0 1 0

# -2 3 -4
# maxval=-2
# minval=-2
# maxprod=-2
# i=3

# maxval= 3,-2*3==max(3,-2*3) =max(3,-6)=3

# minval=min(3,-2*3) ==min(3,-6)= -6

# maxprod=max(minval,maxval)==max(-6,3)==3

# i=-4
# if(-4<0):
#       temp=maxval      temp=3
#       maxval=minval     maxval=-6
#       minval=temp       minval =3
      


# maxval=max(-4,-4*3)==max(-4,-12)== -4               maxval=max(-4,-4*-6)==max(-4,24)==24

# minval=min(-4,-4*-6)==min(-4,24)==-4                minval=min(-4,-4*3)===min(-4,-12)== -12


# maxprod=max(-4,-4)=-4                                maxprod=24

# -2 3 -4 -5
#   i=-5
  
#                                            temp=maxval      temp=24
#                                           maxval=minval    maxval = -12
#                                           minval=temp      mival=24
  
  
  
#   maxval=max(-5,-5*-4)==max(-5,20)== 20    maxval=max(-5,-5*-12)==max(-5,60)==60
  
#   minval=min(-5,-5*-4)=min(-5,20)= -5      minval=min(-5,-5*24)=min(-5,-120)==-120
  
#   maxprod=max(20,-5)==20                  maxprod=max(60,-120)==60
  
# class Node:
#       def __init__(self, x):
#             self.val = x
#             self.left = None
#             self.right = None
# def minDepth(root):
#       if(root is None):
#             return 0
#       children=[root.left,root.right]
     
#       if(not any(children)):
#             return 1
#       min_depth=float("inf")
#       for c in children:
#             if(c):
#                   min_depth=min(minDepth(c),min_depth)
#       return min_depth+1
# root = Node(3)
# root.left = Node(9)
# root.right = Node(20)
# root.right.left=Node(15)
# root.right.right=Node(7)
# actual = minDepth(root)
# print(actual)


# n=7
# l=[5,2,7,4,1,6,3]
# k=3

# def minSwaps(input1,input2,input3):

#       global c
#       c=0
#       j=0
#       def right(l,n):
#             if n>len(l):
#                   n= int(n%len(l))
#             l = (l[-n:] + l[:-n])
#             return l
#       l_d=right(input2,input3)
#       def swap(l,i,j):
#             global c
#             c+=1
#             l[i],l[j]=l[j],l[i]
#             return l
#       for i in range(len(input2)):
#             if(input2==l_d):
#                   break
#             if(input2[i]!=l_d[j]):
#                   idx=input2.index(l_d[j])
#                   j+=1
#                   swap(input2,i,idx)
#       return c
# print(minSwaps(7,[5,2,7,4,1,6,3],3))
            
            
# input1=5
# input2=[2,0,2,0,0]
# input3=[1,0,-1,0,0]
# input4=3

# def phermone(input1,input2,input3,input4):
#       i=0
#       total=input2
#       while(i<input4):
#             aux=[0]*input1
#             for j in range(i,input1):
#                   if(input3[j]==1):
#                         aux[j+1]+=input2[j]
#                   if(input3[j]==0):
#                         continue
#                   if(input3[j]==-1):
#                         aux[j-1]+=input2[j]

#             i+=1
#             print(aux)
#             for k in range(input1):
#                   total[k]=total[k]+aux[k]
#       print(total)
      
      
# print(phermone(input1,input2,input3,input4))
from math import floor
m,n=map(int,input().split())
print(floor((m*n)/2))             
                  
                  
                  
            