```json
{
  "sym_variables": [
    ("x0", "hours worked by Paul"),
    ("x1", "hours worked by John"),
    ("x2", "hours worked by George"),
    ("x3", "hours worked by Jean")
  ],
  "objective_function": "8*x0 + 5*x1 + 5*x2 + 1*x3",
  "constraints": [
    "11.95*x0 + 9.41*x1 + 1.0*x2 + 9.61*x3 <= 251",
    "10.16*x0 + 1.95*x1 + 0.61*x2 + 5.35*x3 <= 115",
    "0.14*x0 + 11.97*x1 + 10.43*x2 + 9.93*x3 <= 81",
    "9.41*x1 + 9.61*x3 >= 27",
    "1.0*x2 + 9.61*x3 >= 21",
    "9.41*x1 + 1.0*x2 >= 25",
    "11.95*x0 + 9.41*x1 >= 47",
    "11.95*x0 + 1.0*x2 + 9.61*x3 >= 49",
    "11.95*x0 + 9.41*x1 + 1.0*x2 + 9.61*x3 >= 49",
    "10.16*x0 + 5.35*x3 >= 24",
    "0.61*x2 + 5.35*x3 >= 17",
    "1.95*x1 + 5.35*x3 >= 9",
    "1.95*x1 + 0.61*x2 + 5.35*x3 >= 28",
    "10.16*x0 + 1.95*x1 + 5.35*x3 >= 28",
    "1.95*x1 + 0.61*x2 + 5.35*x3 >= 28",
    "10.16*x0 + 1.95*x1 + 5.35*x3 >= 28",
    "10.16*x0 + 1.95*x1 + 0.61*x2 + 5.35*x3 >= 28",
    "10.43*x2 + 9.93*x3 >= 19",
    "0.14*x0 + 10.43*x2 >= 20",
    "11.97*x1 + 9.93*x3 >= 8",
    "0.14*x0 + 9.93*x3 >= 9",
    "0.14*x0 + 11.97*x1 + 10.43*x2 >= 19",
    "0.14*x0 + 11.97*x1 + 10.43*x2 + 9.93*x3 >= 19",
    "6*x0 - 8*x2 >= 0",
    "8*x1 - 8*x3 >= 0",
    "11.95*x0 + 9.41*x1 + 9.61*x3 <= 162",
    "1.95*x1 + 0.61*x2 <= 89",
    "1.95*x1 + 0.61*x2 + 5.35*x3 <= 94",
    "10.16*x0 + 0.61*x2 + 5.35*x3 <= 89",
    "10.16*x0 + 1.95*x1 + 0.61*x2 <= 108",
    "11.97*x1 + 9.93*x3 <= 32",
    "0.14*x0 + 10.43*x2 <= 26",
    "x0 >= 0",
    "x1 >= 0",
    "x2 >= 0",
    "x3 >= 0"
  ]
}
```

```python
import gurobipy as gp

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

# Create variables
paul = m.addVar(lb=0, vtype=gp.GRB.CONTINUOUS, name="Paul")
john = m.addVar(lb=0, vtype=gp.GRB.CONTINUOUS, name="John")
george = m.addVar(lb=0, vtype=gp.GRB.CONTINUOUS, name="George")
jean = m.addVar(lb=0, vtype=gp.GRB.CONTINUOUS, name="Jean")


# Set objective function
m.setObjective(8 * paul + 5 * john + 5 * george + 1 * jean, gp.GRB.MINIMIZE)

# Add constraints
m.addConstr(11.95 * paul + 9.41 * john + 1.0 * george + 9.61 * jean <= 251, "r0")
m.addConstr(10.16 * paul + 1.95 * john + 0.61 * george + 5.35 * jean <= 115, "r1")
m.addConstr(0.14 * paul + 11.97 * john + 10.43 * george + 9.93 * jean <= 81, "r2")

m.addConstr(9.41 * john + 9.61 * jean >= 27, "c1")
m.addConstr(1.0 * george + 9.61 * jean >= 21, "c2")
m.addConstr(9.41 * john + 1.0 * george >= 25, "c3")
m.addConstr(11.95 * paul + 9.41 * john >= 47, "c4")
m.addConstr(11.95 * paul + 1.0 * george + 9.61 * jean >= 49, "c5")
m.addConstr(11.95 * paul + 9.41 * john + 1.0 * george + 9.61 * jean >= 49, "c6")

m.addConstr(10.16 * paul + 5.35 * jean >= 24, "c7")
m.addConstr(0.61 * george + 5.35 * jean >= 17, "c8")
m.addConstr(1.95 * john + 5.35 * jean >= 9, "c9")
m.addConstr(1.95 * john + 0.61 * george + 5.35 * jean >= 28, "c10")
m.addConstr(10.16 * paul + 1.95 * john + 5.35 * jean >= 28, "c11")
m.addConstr(1.95 * john + 0.61 * george + 5.35 * jean >= 28, "c12")  # Duplicate constraint
m.addConstr(10.16 * paul + 1.95 * john + 5.35 * jean >= 28, "c13")  # Duplicate constraint
m.addConstr(10.16 * paul + 1.95 * john + 0.61 * george + 5.35 * jean >= 28, "c14")


m.addConstr(10.43 * george + 9.93 * jean >= 19, "c15")
m.addConstr(0.14 * paul + 10.43 * george >= 20, "c16")
m.addConstr(11.97 * john + 9.93 * jean >= 8, "c17")
m.addConstr(0.14 * paul + 9.93 * jean >= 9, "c18")
m.addConstr(0.14 * paul + 11.97 * john + 10.43 * george >= 19, "c19")
m.addConstr(0.14 * paul + 11.97 * john + 10.43 * george + 9.93 * jean >= 19, "c20")

m.addConstr(6 * paul - 8 * george >= 0, "c21")
m.addConstr(8 * john - 8 * jean >= 0, "c22")

m.addConstr(11.95 * paul + 9.41 * john + 9.61 * jean <= 162, "c23")
m.addConstr(1.95 * john + 0.61 * george <= 89, "c24")
m.addConstr(1.95 * john + 0.61 * george + 5.35 * jean <= 94, "c25")
m.addConstr(10.16 * paul + 0.61 * george + 5.35 * jean <= 89, "c26")
m.addConstr(10.16 * paul + 1.95 * john + 0.61 * george <= 108, "c27")
m.addConstr(11.97 * john + 9.93 * jean <= 32, "c28")
m.addConstr(0.14 * paul + 10.43 * george <= 26, "c29")


# Optimize model
m.optimize()

# Print results
if m.status == gp.GRB.OPTIMAL:
    print('Obj: %g' % m.objVal)
    for v in m.getVars():
        print('%s %g' % (v.varName, v.x))
elif m.status == gp.GRB.INFEASIBLE:
    print("The model is infeasible.")
else:
    print("Optimization ended with status %d" % m.status)

```