protected Solution makeHeuristicMove(
      Deadline deadline, Solution s, Random random, HeuristicStats heuristicStats) {
    Heuristic heuristic = heuristicStats.getHeuristic();
    long costBefore = s.getCost();
    long startTime = System.currentTimeMillis();
    s =
        heuristic.move(
            s,
            Deadline.min(new Deadline(heuristicMaxTimes[heuristicStats.getId()]), deadline),
            random);
    long timeDiff = System.currentTimeMillis() - startTime;
    long costDiff = costBefore - s.getCost();

    heuristicStats.saveUsage(timeDiff, costDiff);
    logger.info(
        String.format(
            "Heuristic # %d has improved the solution by %d (%f %%) in %d ms; its last performance = %f",
            heuristicStats.getId(),
            costDiff,
            (double) costDiff * 100 / costBefore,
            timeDiff,
            heuristicStats.getLastPerformance()));

    return s;
  }
  private Solution processHeuristicMove(
      Deadline deadline, Solution s, Random random, HeuristicStats heuristicStats) {
    Heuristic heuristic = heuristicStats.getHeuristic();
    double costBefore = s.getCost();
    s = makeHeuristicMove(deadline, s, random, heuristicStats);
    double costDiff = costBefore - s.getCost();

    if (costDiff > 0) {
      queue.add(heuristicStats);
      for (HeuristicStats stats : exploitedHeuristics) {
        queue.add(stats);
      }
      exploitedHeuristics.clear();
    } else if (heuristic.isDeterministic()) {
      exploitedHeuristics.add(heuristicStats);
    } else {
      queue.add(heuristicStats);
    }

    return s;
  }