Here's the Gurobi code to solve the poster optimization problem:

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

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

# Define decision variables
northside = model.addVar(vtype=GRB.INTEGER, name="northside")
southside = model.addVar(vtype=GRB.INTEGER, name="southside")
central = model.addVar(vtype=GRB.INTEGER, name="central")

# Set objective function: Maximize viewership
model.setObjective(20000 * northside + 50000 * southside + 40000 * central, GRB.MAXIMIZE)

# Add constraints
model.addConstr(500 * northside + 1000 * southside + 800 * central <= 30000, "Budget")  # Budget constraint
model.addConstr(southside <= 5, "SouthsideLimit")  # Southside mall limit
model.addConstr(central <= (northside + southside + central) / 3, "CentralLimit")  # Central mall limit
model.addConstr(northside >= 0.2 * (northside + southside + central), "NorthsideMinimum")  # Northside mall minimum

# Optimize model
model.optimize()

# Print results
if model.status == GRB.OPTIMAL:
    print(f"Number of posters at Northside Mall: {northside.x}")
    print(f"Number of posters at Southside Mall: {southside.x}")
    print(f"Number of posters at Central Mall: {central.x}")
    print(f"Total Viewership: {model.objVal}")
elif model.status == GRB.INFEASIBLE:
    print("The model is infeasible.")
else:
    print(f"Optimization ended with status {model.status}")

```
