def fgh_heuristic(frame: JobSchedulingFrame, count_alpha: int = 1) -> list:
    init_jobs = [idx_job for idx_job in range(frame.count_jobs)]
    sum_times = [
        frame.get_sum_processing_time(idx_job) for idx_job in init_jobs
    ]
    tetta = sum(sum_times) / frame.count_jobs

    time_min = min(sum_times)
    time_max = max(sum_times)
    alpha_min = time_min / (time_min + tetta)
    alpha_max = time_max / (time_max + tetta)
    period = (alpha_max - alpha_min) / count_alpha

    solutions = []
    for i in range(count_alpha):
        alpha = alpha_max - period * i
        init_jobs.sort(
            key=lambda idx_job: fgh_index(sum_times[idx_job], alpha, tetta),
            reverse=True)
        solutions.append(copy(init_jobs))

    for i in range(count_alpha):
        solutions[i], _ = local_search_partitial_sequence(frame, solutions[i])

    solutions.sort(key=lambda solution: compute_end_time(frame, solution))
    return solutions[0]
def neh_heuristics(frame: JobSchedulingFrame) -> list:
    """
    Compute approximate solution for instance of Flow Job problem by
    NEH heuristic.

    Parameters
    ----------
    frame: JobSchedulingFrame

    Returns
    -------
    solution: list
        sequence of job index

    Notes
    -----
    Journal Paper:
        Nawaz,M., Enscore,Jr.E.E, and Ham,I. (1983) A Heuristics Algorithm for
        the m Machine, n Job Flowshop Sequencing Problem.
        Omega-International Journal of Management Science 11(1), 91-95

    """
    count_jobs = frame.count_jobs

    all_processing_times = [0] * count_jobs
    for j in range(count_jobs):
        all_processing_times[j] = frame.get_sum_processing_time(j)

    init_jobs = [j for j in range(count_jobs)]
    init_jobs.sort(key=lambda x: all_processing_times[x], reverse=True)

    solution, _ = local_search_partitial_sequence(frame, init_jobs)
    return solution