DEV Community

faangmaster
faangmaster

Posted on

Численная проверка решения головоломки про топ 3 из 25 лошадей

Задача следующая:

Есть 25 лошадей. На ипподроме 5 дорожек. Надо определить 3 самые быстрые лошади за минимальное число заездов. Время замерять нельзя. Мы только знаем, кто в каком порядке финиширует. Можно считать, что время за которое каждая лошадь пробегает дистанцию не меняется от заезда к заезду.

Решение

Это можно сделать за 7 забегов.
Разбиваем на 5 групп по пять лошадей. Проводим 5 забегов (по одному на группу).
Из победителей в каждой группе формируем шестой забег. Победитель шестого забега - топ 1.
Формируем седьмой забег из:
1) Второго и третьего места из шестого забега.
2) Второго и третьего места из группы (группа в числе изначальных 5 забегов), из которой победитель шестого забега.
3) Второго места из группы (группа в числе изначальных 5 забегов), из которой лошадь, занявшая второе место в шестом забеге.

Победитель седьмего забега - топ 2, второе место в седьмом забеге - топ 3.

Код проверки

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        boolean debugMode = false;
        int numberOfSimulations = 1000_000;

        for (int simulation = 0; simulation < numberOfSimulations; simulation++) {

            if (simulation % 100000 == 0) {
                System.out.println("Simulation number " + simulation);
            }

            simulate(debugMode);
        }
        System.out.println("No mismatches found, all " + numberOfSimulations + " passed!");
    }

    private static void simulate(boolean debugMode) {
        List<Horse> horses = Horses.init();
        if (debugMode) {
            System.out.println("Initial horses:" + horses);
        }
        List<HorseRace> horseRaces = Horses.splitIntoFiveGroups(horses);
        if (debugMode) {
            System.out.println("Five Groups: " + horseRaces);
        }
        horseRaces.forEach(HorseRace::race);
        if (debugMode) {
            System.out.println("Five Groups After Five Races: " + horseRaces);
        }
        HorseRace sixRace = Horses.getWinnersToFormSixRace(horseRaces);
        if (debugMode) {
            System.out.println("Six Race Before: " + sixRace);
        }
        sixRace.race();
        if (debugMode) {
            System.out.println("Six Race After: " + sixRace);
        }
        Map<Horse, HorseRace> horsesToInitialFiveRaces = Horses.indexHorsesToInitialFiveRaces(horseRaces);
        HorseRace sevenRace = new HorseRace();
        sevenRace.add(sixRace.getSecond());
        sevenRace.add(sixRace.getThird());
        HorseRace raceOfWinnerOfSixRace = horsesToInitialFiveRaces.get(sixRace.getWinner());
        sevenRace.add(raceOfWinnerOfSixRace.getSecond());
        sevenRace.add(raceOfWinnerOfSixRace.getThird());
        HorseRace raceOfSecondOfSixRace = horsesToInitialFiveRaces.get(sixRace.getSecond());
        sevenRace.add(raceOfSecondOfSixRace.getSecond());

        if (debugMode) {
            System.out.println("Seven Race Before: " + sevenRace);
        }
        sevenRace.race();
        if (debugMode) {
            System.out.println("Seven Race After: " + sevenRace);
        }

        List<Horse> identifiedTopThreeBySevenRaces = new ArrayList<>();
        identifiedTopThreeBySevenRaces.add(sixRace.getWinner());
        identifiedTopThreeBySevenRaces.add(sevenRace.getWinner());
        identifiedTopThreeBySevenRaces.add(sevenRace.getSecond());
        List<Horse> expectedTopThree = Horses.copySortAndGetTopThree(horses);
        if (debugMode) {
            System.out.println("Expected top three horses:" + expectedTopThree);
        }
        if (debugMode) {
            System.out.println("identifiedTopThreeBySevenRaces: " + identifiedTopThreeBySevenRaces);
        }

        if (!identifiedTopThreeBySevenRaces.equals(expectedTopThree)) {
            System.out.println("Mismatch found!");
            System.out.println("Expected top three horses:" + expectedTopThree);
            System.out.println("identifiedTopThreeBySevenRaces: " + identifiedTopThreeBySevenRaces);
            throw new RuntimeException("Mismatch found!");
        }
    }
}

class Horses {
    public static List<Horse> init() {
        List<Integer> raceTimes = new ArrayList<>(
                IntStream.range(0, 25)
                        .map(index -> index * 100)
                        .boxed()
                        .toList());
        Collections.shuffle(raceTimes);
        return IntStream.range(0, 25)
                .mapToObj(index -> new Horse(index, raceTimes.get(index)))
                .collect(Collectors.toList());
    }
    public static List<Horse> copySortAndGetTopThree(List<Horse> horses) {
        return horses.stream()
                .map(Horse::new)
                .sorted()
                .limit(3)
                .toList();
    }

    public static List<HorseRace> splitIntoFiveGroups(List<Horse> horses) {
        List<HorseRace> horseRaces = new ArrayList<>();
        for (int i = 0; i < horses.size(); i += 5) {
            HorseRace race = new HorseRace();
            for (int j = i; j < i + 5; j++) {
                race.add(horses.get(j));
            }
            horseRaces.add(race);
        }
        return horseRaces;
    }

    public static HorseRace getWinnersToFormSixRace(List<HorseRace> horseRaces) {
        return new HorseRace(
                horseRaces.stream()
                        .map(HorseRace::getWinner)
                        .collect(Collectors.toList()));
    }

    public static Map<Horse, HorseRace> indexHorsesToInitialFiveRaces(List<HorseRace> horseRaces) {
        Map<Horse, HorseRace> index = new HashMap<>();
        for (HorseRace horseRace : horseRaces) {
            for (Horse horse : horseRace.getHorses()) {
                index.put(horse, horseRace);
            }
        }
        return index;
    }
}

class Horse implements Comparable<Horse> {
    private final int index;
    private final int raceTime;

    public Horse(int index, int raceTime) {
        this.index = index;
        this.raceTime = raceTime;
    }

    public Horse(Horse horse) {
        this.index = horse.index;
        this.raceTime = horse.raceTime;
    }

    @Override
    public String toString() {
        return "Horse{" +
                "index=" + index +
                ", raceTime=" + raceTime +
                '}';
    }

    @Override
    public int compareTo(Horse horse) {
        return this.raceTime - horse.raceTime;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Horse horse = (Horse) o;
        return index == horse.index && raceTime == horse.raceTime;
    }

    @Override
    public int hashCode() {
        return Objects.hash(index, raceTime);
    }
}

class HorseRace {
    private final List<Horse> horses;

    public HorseRace() {
        this.horses = new ArrayList<>();
    }

    public HorseRace(List<Horse> horses) {
        this.horses = horses;
    }

    public void add(Horse horse) {
        if (this.horses.size() >= 5) {
            throw new IllegalArgumentException("Number of horses in a race is limited by 5");
        }
        this.horses.add(horse);
    }

    public List<Horse> getHorses() {
        return this.horses;
    }

    public void race() {
        Collections.sort(horses);
    }

    public Horse getWinner() {
        return horses.getFirst();
    }

    public Horse getSecond() {
        return horses.get(1);
    }

    public Horse getThird() {
        return horses.get(2);
    }

    @Override
    public String toString() {
        return "HorseRace{" +
                "horses=" + horses +
                '}';
    }
}
Enter fullscreen mode Exit fullscreen mode

Второй, немного измененный, вариант, где время забега не целое уникальное число, а случайное вещественное число:

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        boolean debugMode = false;
        int numberOfSimulations = 1000_000;

        for (int simulation = 0; simulation < numberOfSimulations; simulation++) {

            if (simulation % 100000 == 0) {
                System.out.println("Simulation number " + simulation);
            }

            simulate(debugMode);
        }
        System.out.println("No mismatches found, all " + numberOfSimulations + " passed!");
    }

    private static void simulate(boolean debugMode) {
        List<Horse> horses = Horses.init();
        if (debugMode) {
            System.out.println("Initial horses:" + horses);
        }
        List<HorseRace> horseRaces = Horses.splitIntoFiveGroups(horses);
        if (debugMode) {
            System.out.println("Five Groups: " + horseRaces);
        }
        horseRaces.forEach(HorseRace::race);
        if (debugMode) {
            System.out.println("Five Groups After Five Races: " + horseRaces);
        }
        HorseRace sixRace = Horses.getWinnersToFormSixRace(horseRaces);
        if (debugMode) {
            System.out.println("Six Race Before: " + sixRace);
        }
        sixRace.race();
        if (debugMode) {
            System.out.println("Six Race After: " + sixRace);
        }
        Map<Horse, HorseRace> horsesToInitialFiveRaces = Horses.indexHorsesToInitialFiveRaces(horseRaces);
        HorseRace sevenRace = new HorseRace();
        sevenRace.add(sixRace.getSecond());
        sevenRace.add(sixRace.getThird());
        HorseRace raceOfWinnerOfSixRace = horsesToInitialFiveRaces.get(sixRace.getWinner());
        sevenRace.add(raceOfWinnerOfSixRace.getSecond());
        sevenRace.add(raceOfWinnerOfSixRace.getThird());
        HorseRace raceOfSecondOfSixRace = horsesToInitialFiveRaces.get(sixRace.getSecond());
        sevenRace.add(raceOfSecondOfSixRace.getSecond());

        if (debugMode) {
            System.out.println("Seven Race Before: " + sevenRace);
        }
        sevenRace.race();
        if (debugMode) {
            System.out.println("Seven Race After: " + sevenRace);
        }

        List<Horse> identifiedTopThreeBySevenRaces = new ArrayList<>();
        identifiedTopThreeBySevenRaces.add(sixRace.getWinner());
        identifiedTopThreeBySevenRaces.add(sevenRace.getWinner());
        identifiedTopThreeBySevenRaces.add(sevenRace.getSecond());
        List<Horse> expectedTopThree = Horses.copySortAndGetTopThree(horses);
        if (debugMode) {
            System.out.println("Expected top three horses:" + expectedTopThree);
        }
        if (debugMode) {
            System.out.println("identifiedTopThreeBySevenRaces: " + identifiedTopThreeBySevenRaces);
        }

        if (!identifiedTopThreeBySevenRaces.equals(expectedTopThree)) {
            System.out.println("Mismatch found!");
            System.out.println("Expected top three horses:" + expectedTopThree);
            System.out.println("identifiedTopThreeBySevenRaces: " + identifiedTopThreeBySevenRaces);
            throw new RuntimeException("Mismatch found!");
        }
    }
}

class Horses {
    public static List<Horse> init() {
        Random random = new Random();
        return IntStream.range(0, 25)
                .mapToObj(index -> new Horse(index, random.nextDouble()))
                .collect(Collectors.toList());
    }
    public static List<Horse> copySortAndGetTopThree(List<Horse> horses) {
        return horses.stream()
                .map(Horse::new)
                .sorted()
                .limit(3)
                .toList();
    }

    public static List<HorseRace> splitIntoFiveGroups(List<Horse> horses) {
        List<HorseRace> horseRaces = new ArrayList<>();
        for (int i = 0; i < horses.size(); i += 5) {
            HorseRace race = new HorseRace();
            for (int j = i; j < i + 5; j++) {
                race.add(horses.get(j));
            }
            horseRaces.add(race);
        }
        return horseRaces;
    }

    public static HorseRace getWinnersToFormSixRace(List<HorseRace> horseRaces) {
        return new HorseRace(
                horseRaces.stream()
                        .map(HorseRace::getWinner)
                        .collect(Collectors.toList()));
    }

    public static Map<Horse, HorseRace> indexHorsesToInitialFiveRaces(List<HorseRace> horseRaces) {
        Map<Horse, HorseRace> index = new HashMap<>();
        for (HorseRace horseRace : horseRaces) {
            for (Horse horse : horseRace.getHorses()) {
                index.put(horse, horseRace);
            }
        }
        return index;
    }
}

class Horse implements Comparable<Horse> {
    private final int index;
    private final double raceTime;

    public Horse(int index, double raceTime) {
        this.index = index;
        this.raceTime = raceTime;
    }

    public Horse(Horse horse) {
        this.index = horse.index;
        this.raceTime = horse.raceTime;
    }

    @Override
    public String toString() {
        return "Horse{" +
                "index=" + index +
                ", raceTime=" + raceTime +
                '}';
    }

    @Override
    public int compareTo(Horse horse) {
        return Double.compare(this.raceTime, horse.raceTime);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Horse horse = (Horse) o;
        return index == horse.index;
    }

    @Override
    public int hashCode() {
        return Objects.hash(index);
    }
}

class HorseRace {
    private final List<Horse> horses;

    public HorseRace() {
        this.horses = new ArrayList<>();
    }

    public HorseRace(List<Horse> horses) {
        this.horses = horses;
    }

    public void add(Horse horse) {
        if (this.horses.size() >= 5) {
            throw new IllegalArgumentException("Number of horses in a race is limited by 5");
        }
        this.horses.add(horse);
    }

    public List<Horse> getHorses() {
        return this.horses;
    }

    public void race() {
        Collections.sort(horses);
    }

    public Horse getWinner() {
        return horses.getFirst();
    }

    public Horse getSecond() {
        return horses.get(1);
    }

    public Horse getThird() {
        return horses.get(2);
    }

    @Override
    public String toString() {
        return "HorseRace{" +
                "horses=" + horses +
                '}';
    }
}
Enter fullscreen mode Exit fullscreen mode

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay