# Complete GUROBIPY implementation

import gurobipy as gp
from gurobipy import GRB

def optimize_captain_assignment():
    """Optimize the assignment of captains to ships to minimize total age."""
    
    # 1. MODEL & DATA SETUP
    model = gp.Model("ship_1")
    
    # Data: Captains and their ages
    captains = [1, 2, 3]
    ages = {1: 45, 2: 50, 3: 55}
    
    # Data: Ships
    ships = [101, 102, 103]
    
    # Validate data lengths
    assert len(captains) == len(ages), "Mismatch in captains and ages data"
    
    # 2. VARIABLES
    # Decision variables: x[i, j] = 1 if captain i is assigned to ship j
    x = model.addVars(captains, ships, vtype=GRB.BINARY, name="x")
    
    # 3. OBJECTIVE FUNCTION
    # Minimize the total age of captains assigned to ships
    model.setObjective(gp.quicksum(ages[i] * x[i, j] for i in captains for j in ships), GRB.MINIMIZE)
    
    # 4. CONSTRAINTS
    # Each captain is assigned to exactly one ship
    model.addConstrs((gp.quicksum(x[i, j] for j in ships) == 1 for i in captains), name="captain_assignment")
    
    # Each ship has exactly one captain
    model.addConstrs((gp.quicksum(x[i, j] for i in captains) == 1 for j in ships), name="ship_assignment")
    
    # Only eligible captains (age ≤ 60) can be assigned
    model.addConstrs((x[i, j] == 0 for i in captains for j in ships if ages[i] > 60), name="age_limit")
    
    # 5. SOLVING & RESULTS
    model.optimize()
    
    if model.status == GRB.OPTIMAL:
        print(f"Optimal value: {model.objVal}")
        for i in captains:
            for j in ships:
                if x[i, j].x > 1e-6:
                    print(f"Captain {i} is assigned to Ship {j}")
    elif model.status == GRB.INFEASIBLE:
        print("Problem is infeasible")
    elif model.status == GRB.UNBOUNDED:
        print("Problem is unbounded")
    
    return model

# Run the optimization
optimize_captain_assignment()