我正在尝试使用遗传算法为教室中的给定部分安排随机座位列表,以便该教室中的所有小组坐在一起。
这是我目前的尝试,我不清楚改进此算法的最佳方法,因为这是我 GA 学习的早期阶段。
我正在使用 Java 库 Jenetics,它非常适合我入门,这里是引擎。
final Engine<EnumGene<Seat>, Double> ENGINE = Engine
.builder(SeatingFitness::fitness, encoding)
.populationSize(200)
.selector(new RouletteWheelSelector<>())
.alterers(
new PartiallyMatchedCrossover<>(0.2),
new Mutator<>(0.01)
)
.optimize(Optimize.MINIMUM)
.build();
编码看起来像这样
static final ISeq<Seat> seats = ISeq.of(createSeats());
static final Codec<ISeq<Seat>, EnumGene<Seat>> encoding = Codecs.ofPermutation(seats);
public static List<Seat> createSeats() {
return new ArrayList<>(Arrays.asList(
new Seat("Group C", 1),
new Seat("Group A", 2),
new Seat("Group B", 3)
.....more seats here....)
}
我的健身功能肯定可以提高,我没有使用任何库,所以这里的任何建议都会很棒,但看起来像这样。
基本上我所做的只是找到组中每个座位的 x 和 y 坐标,并计算每个座位与组中其他座位的距离,并将这些值相加。值越低越好,因此Optimize.MINIMUM
在引擎中
private static int numberOfSeatsInRow = 8;
public static double fitness(final ISeq<Seat> seats) {
AtomicDouble score = new AtomicDouble();
// Group together all the seats that belong to a particular group.
Map<String, List<Seat>> grouping = seats.stream().collect(groupingBy(Seat::getGroup));
grouping.forEach((group, groupsSeats) -> {
// Find the location in the overall list of the seats for the group.
if (!group.equals(Seat.EMPTY_SEAT)) {
List<Integer> indexOfSeatInOverallList = groupsSeats.stream().map(seats::indexOf).collect(Collectors.toList());
if (indexOfSeatInOverallList.size() > 2) {
// Get the first element positioned correctly on the x and y axis
double totalCalculated = indexOfSeatInOverallList.stream().reduce(0, (subTotal, currentElement) -> {
int xReferenceCoordinate = calculateXCoordinate(currentElement);
int yReferenceCoordinate = calculateYCoordinate(currentElement);
double totalDistance = 0;
int multiplier = groupsSeats.size() <= numberOfSeatsInRow ? 10 : 500;
for (Integer integer : indexOfSeatInOverallList) {
int xSecondary = calculateXCoordinate(integer);
int ySecondary = calculateYCoordinate(integer);
if (ySecondary != yReferenceCoordinate) {
totalDistance += multiplier * Math.abs(yReferenceCoordinate - ySecondary);
}
totalDistance += calculateDistanceBetweenTwoPoints(xReferenceCoordinate, yReferenceCoordinate, xSecondary, ySecondary);
}
return (int) totalDistance;
});
score.getAndAdd(totalCalculated);
}
}
});
return score.get();
}
private static int calculateXCoordinate(int positionInList) {
int xPosition = positionInList % numberOfSeatsInRow;
if (xPosition == 0) {
xPosition = numberOfSeatsInRow;
}
return xPosition;
}
private static int calculateYCoordinate(int positionInList) {
int xPosition = positionInList % numberOfSeatsInRow;
int yPosition = positionInList / numberOfSeatsInRow;
if (xPosition == 0) {
yPosition = yPosition - 1;
}
return yPosition + 1;
}
private static double calculateDistanceBetweenTwoPoints(int x1, int y1, int x2, int y2) {
// https://dqydj.com/2d-distance-calculator/
double xValue = Math.pow((x2 - x1), 2);
double yValue = Math.pow((y2 - y1), 2);
return Math.sqrt(xValue + yValue);
}
请参阅下面的结果图像,您可以看到它非常好(尽管运行大约需要 3 分钟才能产生正确的结果)。