```json
{
  "sym_variables": [
    ("x0", "hours worked by Bill"),
    ("x1", "hours worked by Mary"),
    ("x2", "hours worked by Hank")
  ],
  "objective_function": "9.62 * x0 + 6.74 * x1 + 7.61 * x2",
  "constraints": [
    "4.81 * x0 + 10.91 * x1 >= 18",
    "4.81 * x0 + 10.91 * x1 + 7.87 * x2 >= 18",
    "10.28 * x0 + 0.89 * x1 + 11.33 * x2 >= 34",
    "0.62 * x0 + 8.79 * x2 >= 14",
    "11.77 * x1 + 8.79 * x2 >= 37",
    "5.35 * x0 + 8.39 * x1 + 11.28 * x2 >= 28",
    "11.19 * x1 + 9.05 * x2 <= 75",
    "9.76 * x0 + 11.19 * x1 + 9.05 * x2 <= 75",
    "4.81 * x0 + 7.87 * x2 <= 51",
    "4.81 * x0 + 10.91 * x1 + 7.87 * x2 <= 51",
    "10.28 * x0 + 11.33 * x2 <= 83",
    "0.89 * x1 + 11.33 * x2 <= 64",
    "10.28 * x0 + 0.89 * x1 + 11.33 * x2 <= 64",
    "0.62 * x0 + 8.79 * x2 <= 38",
    "11.77 * x1 + 8.79 * x2 <= 86",
    "0.62 * x0 + 11.77 * x1 + 8.79 * x2 <= 86",
    "5.35 * x0 + 8.39 * x1 <= 105",
    "5.35 * x0 + 11.28 * x2 <= 110",
    "5.35 * x0 + 8.39 * x1 + 11.28 * x2 <= 110",
    "x0 >= 0",
    "x1 >= 0",
    "x2 >= 0"
  ]
}
```

```python
import gurobipy as gp

# Create a new model
m = gp.Model("resource_allocation")

# Create variables
bill_hours = m.addVar(lb=0, vtype=gp.GRB.CONTINUOUS, name="bill_hours")
mary_hours = m.addVar(lb=0, vtype=gp.GRB.CONTINUOUS, name="mary_hours")
hank_hours = m.addVar(lb=0, vtype=gp.GRB.CONTINUOUS, name="hank_hours")


# Set objective function
m.setObjective(9.62 * bill_hours + 6.74 * mary_hours + 7.61 * hank_hours, gp.GRB.MAXIMIZE)

# Add constraints
m.addConstr(4.81 * bill_hours + 10.91 * mary_hours >= 18)
m.addConstr(4.81 * bill_hours + 10.91 * mary_hours + 7.87 * hank_hours >= 18)
m.addConstr(10.28 * bill_hours + 0.89 * mary_hours + 11.33 * hank_hours >= 34)
m.addConstr(0.62 * bill_hours + 8.79 * hank_hours >= 14)
m.addConstr(11.77 * mary_hours + 8.79 * hank_hours >= 37)
m.addConstr(5.35 * bill_hours + 8.39 * mary_hours + 11.28 * hank_hours >= 28)
m.addConstr(11.19 * mary_hours + 9.05 * hank_hours <= 75)
m.addConstr(9.76 * bill_hours + 11.19 * mary_hours + 9.05 * hank_hours <= 75)
m.addConstr(4.81 * bill_hours + 7.87 * hank_hours <= 51)
m.addConstr(4.81 * bill_hours + 10.91 * mary_hours + 7.87 * hank_hours <= 51)
m.addConstr(10.28 * bill_hours + 11.33 * hank_hours <= 83)
m.addConstr(0.89 * mary_hours + 11.33 * hank_hours <= 64)
m.addConstr(10.28 * bill_hours + 0.89 * mary_hours + 11.33 * hank_hours <= 64)
m.addConstr(0.62 * bill_hours + 8.79 * hank_hours <= 38)
m.addConstr(11.77 * mary_hours + 8.79 * hank_hours <= 86)
m.addConstr(0.62 * bill_hours + 11.77 * mary_hours + 8.79 * hank_hours <= 86)
m.addConstr(5.35 * bill_hours + 8.39 * mary_hours <= 105)
m.addConstr(5.35 * bill_hours + 11.28 * hank_hours <= 110)
m.addConstr(5.35 * bill_hours + 8.39 * mary_hours + 11.28 * hank_hours <= 110)


# Optimize model
m.optimize()

# Print results
if m.status == gp.GRB.OPTIMAL:
    print('Obj: %g' % m.objVal)
    print('Bill Hours: %g' % bill_hours.x)
    print('Mary Hours: %g' % mary_hours.x)
    print('Hank Hours: %g' % hank_hours.x)
elif m.status == gp.GRB.INFEASIBLE:
    print('Model is infeasible')
else:
    print('Optimization ended with status %d' % m.status)

```