## Problem Description and Formulation

The problem is an optimization problem with integer variables and constraints. The goal is to minimize an objective function subject to various constraints on the umami index contributed by different food items: bagged salads, hamburgers, bananas, and protein bars.

## Variables and Objective Function

- Variables: 
  - $x_0$: bagged salads
  - $x_1$: hamburgers
  - $x_2$: bananas
  - $x_3$: protein bars

- Objective Function: Minimize $6.71x_0 + 9.86x_1 + 1.3x_2 + 8.97x_3$

## Constraints

1. Umami index from each item:
   - Bagged salads: $14.62x_0$
   - Hamburgers: $3.71x_1$
   - Bananas: $15.89x_2$
   - Protein bars: $6.29x_3$

2. Constraints:
   - $15.89x_2 + 6.29x_3 \geq 65$
   - $14.62x_0 + 3.71x_1 \geq 39$
   - $3.71x_1 + 6.29x_3 \geq 40$
   - $14.62x_0 + 3.71x_1 + 15.89x_2 \geq 44$
   - $3.71x_1 + 15.89x_2 + 6.29x_3 \geq 44$
   - $14.62x_0 + 3.71x_1 + 15.89x_2 \geq 49$
   - $3.71x_1 + 15.89x_2 + 6.29x_3 \geq 49$
   - $14.62x_0 + 3.71x_1 + 15.89x_2 + 6.29x_3 \geq 49$
   - $5x_0 - 3x_2 + 5x_3 \geq 0$
   - $3.71x_1 + 15.89x_2 \leq 197$
   - $14.62x_0 + 6.29x_3 \leq 143$
   - $14.62x_0 + 15.89x_2 \leq 195$
   - $3.71x_1 + 6.29x_3 \leq 285$
   - $15.89x_2 + 6.29x_3 \leq 281$
   - $14.62x_0 + 3.71x_1 + 6.29x_3 \leq 157$
   - $14.62x_0 + 3.71x_1 + 15.89x_2 \leq 306$
   - $3.71x_1 + 15.89x_2 + 6.29x_3 \leq 220$

## Gurobi Code

```python
import gurobi

def optimization_problem():
    # Create a new model
    m = gurobi.Model()

    # Define variables
    x0 = m.addVar(name="bagged_salads", vtype=gurobi.GRB.INTEGER)
    x1 = m.addVar(name="hamburgers", vtype=gurobi.GRB.INTEGER)
    x2 = m.addVar(name="bananas", vtype=gurobi.GRB.INTEGER)
    x3 = m.addVar(name="protein_bars", vtype=gurobi.GRB.INTEGER)

    # Objective function
    m.setObjective(6.71 * x0 + 9.86 * x1 + 1.3 * x2 + 8.97 * x3, gurobi.GRB.MINIMIZE)

    # Constraints
    m.addConstr(15.89 * x2 + 6.29 * x3 >= 65)
    m.addConstr(14.62 * x0 + 3.71 * x1 >= 39)
    m.addConstr(3.71 * x1 + 6.29 * x3 >= 40)
    m.addConstr(14.62 * x0 + 3.71 * x1 + 15.89 * x2 >= 44)
    m.addConstr(3.71 * x1 + 15.89 * x2 + 6.29 * x3 >= 44)
    m.addConstr(14.62 * x0 + 3.71 * x1 + 15.89 * x2 >= 49)
    m.addConstr(3.71 * x1 + 15.89 * x2 + 6.29 * x3 >= 49)
    m.addConstr(14.62 * x0 + 3.71 * x1 + 15.89 * x2 + 6.29 * x3 >= 49)
    m.addConstr(5 * x0 - 3 * x2 + 5 * x3 >= 0)
    m.addConstr(3.71 * x1 + 15.89 * x2 <= 197)
    m.addConstr(14.62 * x0 + 6.29 * x3 <= 143)
    m.addConstr(14.62 * x0 + 15.89 * x2 <= 195)
    m.addConstr(3.71 * x1 + 6.29 * x3 <= 285)
    m.addConstr(15.89 * x2 + 6.29 * x3 <= 281)
    m.addConstr(14.62 * x0 + 3.71 * x1 + 6.29 * x3 <= 157)
    m.addConstr(14.62 * x0 + 3.71 * x1 + 15.89 * x2 <= 306)
    m.addConstr(3.71 * x1 + 15.89 * x2 + 6.29 * x3 <= 220)

    # Set upper bound for umami index
    m.addConstr(14.62 * x0 + 3.71 * x1 + 15.89 * x2 + 6.29 * x3 <= 311)

    # Solve the problem
    m.optimize()

    # Print the status
    if m.status == gurobi.GRB.Status.OPTIMAL:
        print("Optimal solution found.")
        print("Objective: ", m.objVal)
        print("Bagged Salads: ", x0.varValue)
        print("Hamburgers: ", x1.varValue)
        print("Bananas: ", x2.varValue)
        print("Protein Bars: ", x3.varValue)
    elif m.status == gurobi.GRB.Status.INFEASIBLE:
        print("The problem is infeasible.")
    else:
        print("The problem has a non-optimal status.")

optimization_problem()
```