Now, from 6 individuals (A, B, C, D, E, F), 5 are to be selected to complete 5 tasks (1-5). The time each person takes to complete each task is shown in the table below:

| task\person | A | B | C | D | E | F |
|---|---|---|---|---|---|---|
| 1 | 5 | 2 | 3 | 15 | 9 | 10 |
| 2 | 5 | 6 | 15 | 2 | 4 | 7 |
| 3 | 15 | 5 | 14 | 7 | 15 | 6 |
| 4 | 20 | 15 | 18 | 6 | 8 | 11 |
| 5 | 8 | 11 | 18 | 10 | 15 | 6 |

It is stipulated that each person can only complete one task. Due to certain reasons, individual A must be assigned a task, and individual D cannot be assigned task 4. What is the minimum total time spent?

Problem type: ILP (Medium: 30 variables, 13 constraints, 66 nonzeros)

Mathematical model:
Set:
1. Person
The set of persons, \( P = \{A, B, \dots, F\} \)
2. Tasks
The set of tasks, \( T = \{1, 2, \dots, 5\} \)

Parameter:
1. PersonNum
6
2. TaskNum
5
3. CompleteTime
[[5, 2, 3, 15, 9, 10], [5, 6, 15, 2, 4, 7], [15, 5, 14, 7, 15, 6], [20, 15, 18, 6, 8, 11], [8, 11, 18, 10, 15, 6]]

Decision variable:
1. Assignment
Binary variable, \( x_{ij} \) for all \( i \in P, j \in T \), representing whether person \( i \) is assigned to task \( j \) (1 if assigned, 0 otherwise)

Objective:
The total time spent
min: \sum_{i\in P}\sum_{j\in T}CompleteTime_{ij}\cdot x_{ij}

Constraint:
1. Person assignment
\sum_{j\in T}x_{ij} \leq 1, \forall i \in P
2. Task assignment
\sum_{i\in P}x_{ij} = 1, \forall j \in T
3. Person A 
\sum_{j\in T}x_{P[0]j} = 1
4. Person D 
x_{P[3]j} = 0, \forall j \in T

Type:
Integer, Linear, Linear
ILP

Gurobi implementation:
import gurobipy as gp
from gurobipy import GRB


def solve_task_assignment(
    complete_time=[
        [5, 2, 3, 15, 9, 10],
        [5, 6, 15, 2, 4, 7],
        [15, 5, 14, 7, 15, 6],
        [20, 15, 18, 6, 8, 11],
        [8, 11, 18, 10, 15, 6],
    ]
):
    """
    Models and solves the task assignment problem.
    """
    # --- 1. Model Creation ---
    model = gp.Model("TaskAssignment")

    # --- 2. Sets ---
    # The number of tasks is the number of rows in complete_time.
    # The number of persons is the number of columns.
    num_tasks = len(complete_time)
    num_persons = len(complete_time[0])
    tasks = range(num_tasks)
    persons = range(num_persons)

    # --- 3. Decision Variables ---
    # x[p, t] = 1 if person p is assigned to task t, 0 otherwise
    x = model.addVars(persons, tasks, vtype=GRB.BINARY, name="assign")

    # --- 4. Objective Function ---
    # Minimize total completion time. Note: complete_time is indexed by [task][person].
    objective = gp.quicksum(complete_time[t][p] * x[p, t]
                           for p in persons for t in tasks)
    model.setObjective(objective, GRB.MINIMIZE)

    # --- 5. Constraints ---
    # Constraint 1: Each person can be assigned to at most one task.
    for p in persons:
        model.addConstr(gp.quicksum(x[p, t] for t in tasks) <= 1,
                        name=f"person_at_most_one_task_{p}")

    # Constraint 2: Each task must be assigned to exactly one person.
    for t in tasks:
        model.addConstr(gp.quicksum(x[p, t] for p in persons) == 1,
                        name=f"task_must_be_assigned_{t}")

    # Constraint 3: Person A (index 0) must be assigned to exactly one task.
    # This makes the general constraint (<=1) redundant for Person A, but is included
    # to match the problem's specific requirements.
    model.addConstr(gp.quicksum(x[0, t] for t in tasks) == 1,
                    name="person_A_must_work")

    # Constraint 4: Person D (index 3) cannot be assigned to task 4 (index 3).
    model.addConstr(x[3, 3] == 0, name="person_D_task_4_restriction")

    # --- 6. Solve the Model ---
    model.setParam("OutputFlag", 0)  # Suppress Gurobi output
    model.optimize()

    # --- 7. Return Results ---
    if model.status == GRB.OPTIMAL:
        return {"status": "optimal", "obj": model.ObjVal}
    else:
        return {"status": f"{model.status}"}


# Run the solver function
if __name__ == "__main__":
    result = solve_task_assignment()
    print(result)


Solution status: OPTIMAL
Optimal objective value: 26