## Problem Description and Formulation

The problem is a classic example of a linear programming problem. The sign company wants to maximize its profit by determining the optimal number of neon and metal signs to craft and install, given the available hours for crafting and installation.

Let's define the decision variables:

* $N$ = number of neon signs
* $M$ = number of metal signs

The objective function is to maximize the total profit:

Maximize: $200N + 100M$

The constraints are:

* Crafting hours: $3N + 2M \leq 950$
* Installation hours: $2N + 1.5M \leq 400$
* Non-negativity: $N \geq 0, M \geq 0$

## Gurobi Code

```python
import gurobi

def solve_sign_company_problem():
    # Create a new Gurobi model
    model = gurobi.Model()

    # Define the decision variables
    N = model.addVar(lb=0, name="Neon Signs")
    M = model.addVar(lb=0, name="Metal Signs")

    # Define the objective function
    model.setObjective(200 * N + 100 * M, gurobi.GRB.MAXIMIZE)

    # Define the constraints
    model.addConstr(3 * N + 2 * M <= 950, name="Crafting Hours")
    model.addConstr(2 * N + 1.5 * M <= 400, name="Installation Hours")

    # Optimize the model
    model.optimize()

    # Print the solution
    if model.status == gurobi.GRB.OPTIMAL:
        print(f"Optimal solution: Neon Signs = {N.varValue:.2f}, Metal Signs = {M.varValue:.2f}")
        print(f"Maximum profit: ${model.objVal:.2f}")
    else:
        print("No optimal solution found")

# Run the function
solve_sign_company_problem()
```

This code defines the decision variables, objective function, and constraints, and then solves the model using Gurobi's optimization algorithm. The solution is printed to the console, including the optimal number of neon and metal signs and the maximum profit. If no optimal solution is found, a message indicating this is printed instead.