понедельник, 30 апреля 2012 г.

Презервативы

Два мужчины и две женщины оказались на необитаемом острове. Каждый из них болен каким-то венерическим заболеванием, причём все заболевания разные. Как сделать так, чтобы каждый мужчина смог заняться сексом с каждой женщиной, и никто не подхватил нового заболевания, если у них всего 2 презерватива?

воскресенье, 22 апреля 2012 г.

2 пловца

Два пловца одновременно стартуют по одной дорожке от одного бортика бассейна и плавают туда-сюда с постоянными скоростями. Один проплывает бассейн от одного бортика до противоположного за 11 минут, а второй - за 30 минут. Достигнув бортика, они мгновенно разворачиваются и начинают плыть в обратном направлении с прежней скоростью. Пловцы остановятся, когда оба одновременно окажутся у того бортика, с которого они стартовали. Сколько раз за это время быстрый пловец догонит медленного?

Пользуясь случаем, хочу передать привет Рустему, рассказавшему мне эту задачу два года назад.

воскресенье, 15 апреля 2012 г.

Уснуть и видеть сны

Продолжаем исследовать способы выстрелить себе в ногу на Java. Ещё одна головоломка с уже известного нам сайта.

Иногда бывает такое, что я просыпаюсь только для того, чтобы понять, что на самом-то деле я всё ещё сплю. Каждый раз, когда это случается, я чувствую себя несколько не в своей тарелке. Чтобы этого избежать, я начал считать уровни рекурсии, погружаясь в сон:
public class Sleeper {
    private int level;
    public synchronized int enter(Dream dream) {
        level++;
        try {
            dream.dream(this);
        } finally {
            level--;
        }
        return level;
    }
}
Выглядит надёжно, не так ли? Погружаясь в сон, я увеличиваю счётчик. Выходя из сна, я уменьшаю его. Благодаря блоку finally я уверен, что не забуду уменьшить счётчик, даже если на каком-то уровне рекурсии очередной сон выбросит исключение. Поскольку метод объявлен synchronized, я не боюсь, что в мой сон влезет какой-то другой поток.

Теперь я со спокойной душой ложусь спать следующим образом:
public class Main {
    public static void main(String[] args) {
        if (new Sleeper().enter(new Dream()) != 0) {
            // The goal is to reach this line
            System.out.println("Am I still dreaming?");
        }
    }
}
Есть ли ошибка в моих рассуждениях? Можно ли написать такой класс Dream, что он сломает мою программу, и она напечатать помеченную строку? Изменять классы Sleeper и Main нельзя.
public class Dream {
    public void dream(Sleeper s) {
        // TODO implement me
    }
}
Действуют те же ограничения, что и в задаче про клоунов. Вкратце, нельзя использовать reflection и манипулировать байт-кодом на лету. В остальном можете писать неограниченно грязный код, при условии, конечно, что компилятор его съест.

воскресенье, 8 апреля 2012 г.

Как выбрать президента?

Владимир Путин и Дмитрий Медведев решают, кому из них быть президентом. Путин загадал три натуральных числа X, Y и Z, каждое из которых меньше 1000. Медведев должен назвать три натуральных числа A, B и C (не обязательно меньше 1000), после чего Путин сообщит ему сумму A*X+B*Y+C*Z. Чтобы сохранить за собой президентский пост Медведеву нужно будет угадать задуманные числа. Как он может это сделать?

Эту задачу я нашёл на RSDN'е.

воскресенье, 1 апреля 2012 г.

Сколько клоунов влезет в Фольксваген?

Думаю, многие знают цирковой номер, в котором из крохотного Volkswagen Beetle ("Запорожец" по-немецки) вылезает вереница клоунов, которой, кажется, нет конца. Невольно задумаешься: как же их туда упаковали? Смоделируем эту ситуацию программно.

Даны два класса на Java:
public class Clown {
    // nothing
}
public class Volkswagen {
    private static final int CAPACITY = 5;
    private Set<Clown> clowns = new HashSet<Clown>();

    public synchronized void add(Clown clown) {
        if (clowns.size() >= CAPACITY) {
            throw new IllegalStateException("I'm full");
        } else {
            clowns.add(clown);
        }
    }

    public synchronized void done() {
        if (clowns.size() == 20) {
            // The goal is to reach this line
            System.out.println("I'm a Volkswagen with 20 clowns!");
        }
    }
}
Нужно написать код, который в конце концов вызовет done() и напечатает указанную строку. Начать можно с чего-то такого (работать, конечно, этот пример не будет):
public class Clowns {
    public static void main(String args[]) {
        Volkswagen vw = new Volkswagen();
        for (int i=0; i<20; i++) {
            vw.add(new Clown());
        }
        vw.done();
    }
}
Несколько ограничений:
0. Нельзя изменять данные Вам файлы Clowns.java и Volkswagen.java.
1. Программа должна работать с включенным SecurityManager'ом (т.е. с опцией -Djava.security.manager). Поэтому воспользоваться reflection'ом, чтобы изменить private поле, не получится.
2. Никакие другие опции JVM использовать нельзя. В частности, нельзя подсовывать JVM свой подхаченный ClassLoader, чтобы подменить стандартную реализацию java.util.HashMap
3. Должна выполниться именно указанная строка указанного класса, а не другая строка каким-то хитрым образом скопированного или унаследованного класса.

В остальном Вы вольны делать всё, что Вашей душе угодно. Можете писать сколь угодно грязный код, даже если за такое в приличном обществе принято бить канделябром отрывать руки.

Оригинал задачи на английском я нашёл здесь.