## Problem Description and Formulation

The company wants to maximize viewership by purchasing ads in three video categories: DIY videos, shopping videos, and unboxing videos. Each ad in these categories has a different cost and reaches a different number of viewers. The goal is to determine how many ads to place in each category to maximize viewership given a budget of $120,000 and certain constraints on ad placements.

## Decision Variables

Let \(x_1\), \(x_2\), and \(x_3\) be the number of ads placed in DIY, shopping, and unboxing videos, respectively.

## Objective Function

The objective is to maximize the total viewership. The viewership for each ad category is given as 10,000 for DIY, 4,000 for shopping, and 9,000 for unboxing videos. Therefore, the objective function can be formulated as:

\[ \text{Maximize:} \quad 10,000x_1 + 4,000x_2 + 9,000x_3 \]

## Constraints

1. **Budget Constraint:** The total cost of ads should not exceed $120,000. The costs are $5,000 for DIY, $3,200 for shopping, and $4,000 for unboxing videos.

\[ 5,000x_1 + 3,200x_2 + 4,000x_3 \leq 120,000 \]

2. **DIY Ads Limitation:** The number of ads placed in DIY videos is at most 5.

\[ x_1 \leq 5 \]

3. **Unboxing Ads Limitation:** At most half of the total ads should be unboxing videos.

\[ x_3 \leq 0.5(x_1 + x_2 + x_3) \]

\[ 0.5(x_1 + x_2 + x_3) - x_3 \geq 0 \]

\[ 0.5x_1 + 0.5x_2 - 0.5x_3 \geq 0 \]

4. **Shopping Ads Requirement:** At least 20% of ads should be in shopping videos.

\[ x_2 \geq 0.2(x_1 + x_2 + x_3) \]

\[ 0.2(x_1 + x_2 + x_3) - x_2 \leq 0 \]

\[ 0.2x_1 + 0.2x_2 + 0.2x_3 - x_2 \leq 0 \]

\[ 0.2x_1 - 0.8x_2 + 0.2x_3 \leq 0 \]

5. **Non-Negativity Constraint:** The number of ads cannot be negative.

\[ x_1, x_2, x_3 \geq 0 \]

## Gurobi Code

```python
import gurobipy as gp

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

# Decision variables
x1 = m.addVar(name="DIY_ads", lb=0, ub=5, vtype=gp.GRB.INTEGER)  # DIY ads
x2 = m.addVar(name="shopping_ads", lb=0, vtype=gp.GRB.INTEGER)  # Shopping ads
x3 = m.addVar(name="unboxing_ads", lb=0, vtype=gp.GRB.INTEGER)  # Unboxing ads

# Objective: Maximize viewership
m.setObjective(10000*x1 + 4000*x2 + 9000*x3, gp.GRB.MAXIMIZE)

# Budget constraint
m.addConstr(5000*x1 + 3200*x2 + 4000*x3 <= 120000, name="budget_constraint")

# DIY ads limitation
m.addConstr(x1 <= 5, name="diy_limitation")

# Unboxing ads limitation
m.addConstr(0.5*x1 + 0.5*x2 - 0.5*x3 >= 0, name="unboxing_limitation")

# Shopping ads requirement
m.addConstr(0.2*x1 - 0.8*x2 + 0.2*x3 <= 0, name="shopping_requirement")

# Solve the model
m.optimize()

# Print the solution
if m.status == gp.GRB.OPTIMAL:
    print("Optimal Solution:")
    print(f"DIY Ads: {x1.varValue}")
    print(f"Shopping Ads: {x2.varValue}")
    print(f"Unboxing Ads: {x3.varValue}")
    print(f"Max Viewership: {m.objVal}")
else:
    print("No optimal solution found")
```