## Problem Description and Formulation

The film production company wants to maximize viewership by advertising in three areas: malls, bus stops, and theatres, with a weekly budget of $30000. The costs and audience reaches for each area are given as follows:
- Mall: $5000, 50000 viewers
- Bus Stop: $1000, 10000 viewers
- Theatre: $3000, 20000 viewers

Constraints:
1. The total budget is $30000.
2. The number of ads at a bus stop is limited to 20.
3. At most a third of the total number of ads should be in theatres.
4. A minimum of 20% of ads should be in malls.

## Symbolic Representation

Let's denote the number of ads in malls, bus stops, and theatres as \(M\), \(B\), and \(T\) respectively.

The objective function to maximize viewership is:
\[ \text{Maximize:} \quad 50000M + 10000B + 20000T \]

Subject to:
1. Budget constraint: \( 5000M + 1000B + 3000T \leq 30000 \)
2. Bus stop ad limit: \( B \leq 20 \)
3. Theatre ad limit: \( T \leq \frac{1}{3}(M + B + T) \)
4. Mall ad minimum: \( M \geq 0.20(M + B + T) \)
5. Non-negativity: \( M, B, T \geq 0 \) and are integers.

## Gurobi Code

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

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

# Variables
M = model.addVar(name="Malls", vtype=GRB.INTEGER)  # Ads in malls
B = model.addVar(name="Bus_Stops", vtype=GRB.INTEGER)  # Ads at bus stops
T = model.addVar(name="Theatres", vtype=GRB.INTEGER)  # Ads in theatres

# Objective: Maximize viewership
model.setObjective(50000*M + 10000*B + 20000*T, GRB.MAXIMIZE)

# Budget constraint
model.addConstr(5000*M + 1000*B + 3000*T <= 30000, name="Budget")

# Bus stop ad limit
model.addConstr(B <= 20, name="Bus_Stop_Limit")

# Theatre ad limit: at most a third of total ads
model.addConstr(T <= (M + B + T) / 3, name="Theatre_Limit")

# Mall ad minimum: at least 20% of total ads
model.addConstr(M >= 0.20 * (M + B + T), name="Mall_Minimum")

# Non-negativity is inherently handled by adding as integer variables

# Solve the model
model.optimize()

# Print the results
if model.status == GRB.OPTIMAL:
    print("Optimal Solution:")
    print(f"Ads in Malls: {M.varValue}")
    print(f"Ads at Bus Stops: {B.varValue}")
    print(f"Ads in Theatres: {T.varValue}")
    print(f"Max Viewership: {model.objVal}")
else:
    print("The model is infeasible")
```