Here's the formulation of the linear program and the Gurobi code to solve it:

**Decision Variables:**

*  `c`: Number of cleaners
*  `r`: Number of receptionists

**Objective Function:**

Minimize the total weekly wage: `500c + 350r`

**Constraints:**

* **Total Workers:** `c + r >= 100`
* **Minimum Receptionists:** `r >= 20`
* **Receptionist to Cleaner Ratio:** `r >= (1/3)c`  which can be rewritten as `3r >= c`
* **Wage Bill:** `500c + 350r <= 30000`
* **Non-negativity:** `c >= 0`, `r >= 0`


```python
import gurobipy as gp
from gurobipy import GRB

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

# Create decision variables
c = model.addVar(lb=0, vtype=GRB.INTEGER, name="cleaners")
r = model.addVar(lb=0, vtype=GRB.INTEGER, name="receptionists")

# Set objective function
model.setObjective(500*c + 350*r, GRB.MINIMIZE)

# Add constraints
model.addConstr(c + r >= 100, "total_workers")
model.addConstr(r >= 20, "min_receptionists")
model.addConstr(3*r >= c, "receptionist_ratio")
model.addConstr(500*c + 350*r <= 30000, "wage_bill")

# Optimize model
model.optimize()

# Print results
if model.status == GRB.OPTIMAL:
    print(f"Optimal Solution Found:")
    print(f"Number of Cleaners: {c.x}")
    print(f"Number of Receptionists: {r.x}")
    print(f"Total Weekly Wage: ${model.objVal}")
elif model.status == GRB.INFEASIBLE:
    print("Model is infeasible. No solution found.")
else:
    print(f"Optimization terminated with status {model.status}")

```
