Школа Юрия Окунева

Привет, друзья. С вами Юрий Окунев. С советскими пионерами разобрались. Сегодня возьмем планку повыше. Отгадаем загадку Энштейна.

Загадка Эйнштейна - известная логическая задача, авторство которой приписывается Альберту Эйнштейну.

Считается, что эта головоломка была создана Альбертом Эйнштейном в годы его детства. Также бытует мнение, что она использовалась Эйнштейном для проверки кандидатов в ассистенты на способность к логическому мышлению.

Некоторые приписывают Эйнштейну рассуждение, в котором тот утверждает, что лишь два процента населения земного шара способны оперировать в уме закономерностями, связанными сразу с пятью признаками. Как частное следствие этого, приведённая головоломка может быть решена без использования бумаги лишь теми, кто принадлежит к этим двум процентам. Тем не менее, не существует никаких документальных свидетельств того, что Эйнштейн когда-либо утверждал подобное.

В своей самой тяжёлой редакции задача предполагает решение в уме, без использования каких-либо записей или средств сохранения информации. Без этого головоломка заметно теряет в сложности, поскольку может быть решена простым составлением таблицы с исключением заведомо противоречивых вариантов - и следовательно мало что говорит о способностях испытуемого."

5 разных человек в 5 разных домах разного цвета, курят 5 разных марок сигарет, выращивают 5 разных видов животных, пьют 5 разных видов напитков.

Вопрос: кто выращивает рыбок?

Подсказки:

  • Норвежец живет в первом доме.
  • Англичанин живет в красном доме.
  • Зеленый дом находится левее белого.
  • Датчанин пьет чай.
  • Тот, кто курит Rothmans, живет рядом с тем, кто
  • выращивает кошек.
  • Тот, кто живет в желтом доме, курит Dunhill.
  • Немец курит Marlboro.
  • Тот, кто живет в центре, пьет молоко.
  • Сосед того, кто курит Rothmans, пьет воду.
  • Тот, кто курит Pall Mall, выращивает птиц.
  • Швед выращивает собак.
  • Норвежец живет рядом с синим домом.
  • Тот, кто выращивает лошадей, живет в синем доме.
  • Тот, кто курит Philip Morris, пьет пиво.
  • В зеленом доме пьют кофе.

Попробуйте угадать, кто выращивает рыбок?

Тем не менее, нет никаких доказательств того, что задачу придумал Эйнштейн или Кэрролл. Более того, в приведённом ниже условии задачи упоминаются марки сигарет, например Kools, которые не существовали при жизни Кэрролла и во времена детства Эйнштейна.

Некоторые приписывают Эйнштейну рассуждение, в котором тот утверждает, что лишь два процента населения земного шара способны оперировать в уме закономерностями, связанными сразу с пятью признаками . Как частное следствие этого, приведённая головоломка может быть решена без использования бумаги лишь теми, кто принадлежит к этим двум процентам. Однако не существует никаких документальных свидетельств того, что Эйнштейн когда-либо утверждал подобное.

В своём самом сложном варианте задача предполагает решение в уме, без использования каких-либо записей или средств сохранения информации. Без этих ограничений головоломка заметно теряет в сложности, поскольку может быть решена простым составлением таблицы с исключением заведомо противоречивых вариантов, и, следовательно, мало что говорит о способностях испытуемого.

Оригинальный текст задачи

Здесь приведён первый известный опубликованный вариант головоломки, который появился в журнале англ.) в номере от 17 декабря 1962 года . Выпуск от 25 марта 1963 года содержал нижеприведённый ответ и список из нескольких сотен фамилий читателей, правильно решивших задачу.

  1. На улице стоят пять домов.
  2. У испанца есть собака.
  3. В зелёном доме пьют кофе.
  4. Украинец пьёт чай.
  5. Зелёный дом стоит сразу справа от белого дома.
  6. Тот, кто курит Old Gold, разводит улиток.
  7. В жёлтом доме курят Kools.
  8. В центральном доме пьют молоко.
  9. Норвежец живёт в первом доме.
  10. Сосед того, кто курит Chesterfield, держит лису.
  11. В доме по соседству с тем, в котором держат лошадь, курят Kools.
  12. Тот, кто курит Lucky Strike, пьёт апельсиновый сок.
  13. Японец курит Parliament.

Кто пьёт воду? Кто держит зебру?

В целях ясности следует добавить, что каждый из пяти домов окрашен в свой цвет, а их жители - разных национальностей, владеют разными животными, пьют разные напитки и курят разные марки американских сигарет. Ещё одно замечание: в утверждении 6, справа означает справа относительно Вас .

Оригинальный текст (англ.)

  1. There are five houses.
  2. The Englishman lives in the red house.
  3. The Spaniard owns the dog.
  4. Coffee is drunk in the green house.
  5. The Ukrainian drinks tea.
  6. The green house is immediately to the right of the ivory house.
  7. The Old Gold smoker owns snails.
  8. Kools are smoked in the yellow house.
  9. Milk is drunk in the middle house.
  10. The Norwegian lives in the first house.
  11. The man who smokes Chesterfields lives in the house next to the man with the fox.
  12. Kools are smoked in the house next to the house where the horse is kept.
  13. The Lucky Strike smoker drinks orange juice.
  14. The Japanese smokes Parliaments.
  15. The Norwegian lives next to the blue house.

Now, who drinks water? Who owns the zebra?

In the interest of clarity, it must be added that each of the five houses is painted a different color, and their inhabitants are of different national extractions, own different pets, drink different beverages and smoke different brands of American cigarets. One other thing: in statement 6, right means your right.

Исходное условие опускает некоторые существенные детали, в частности то, что дома расположены подряд.

Так как в условии не сказано о том, что кто-либо вообще пьёт воду или держит зебру, то эти утверждения полагаются неявными посылками, как это принято в подобных логических задачах. В противном случае ответом будет «Не хватает данных».

Посылка 12 в оригинале сформулирована не совсем корректно. Она должна гласить «Kools are smoked in a house next to the house where the horse is kept», а не «the house», так как в таком случае «the» подразумевает, что рядом с домом, в котором держат лошадь, находится только один дом, из чего, в свою очередь, следует, что дом с лошадью - либо крайний левый, либо крайний правый. А это в результате приводит к противоречию.

Решение

Здесь приведены дедуктивные шаги, следуя которым можно получить решение. Суть метода заключается в том, чтобы попытаться вписать известные соотношения в таблицу, последовательно исключая невозможные варианты. Ключевые умозаключения выделены курсивом.

Шаг 1

По условию норвежец живёт в первом доме (10). Не имеет значения откуда - слева или справа - ведётся нумерация. Нас интересует только порядок домов, а не направление, в котором они нумеруются.

Из (10) и (15) следует, что второй дом синий. Какого цвета первый дом? Не зелёный и не белый, потому что они должны стоять рядом (это следует из 6-й посылки и того, что 2-й дом синий). Не красный, потому что там живёт англичанин.

Какого цвета первый дом? Он не может быть ни зелёным, ни белым, ведь дома этих двух цветов должны располагаться рядом (3). Красным он тоже не может быть, потому что в красном доме живёт англичанин (2). Поэтому первый дом жёлтый .

Из этого следует, что в первом доме курят Kools (8), а во втором доме держат лошадь (12).

Что пьёт норвежец, который живёт в первом, жёлтом доме и курит Kools? Это не чай, поскольку чай пьёт украинец (5). И не кофе, потому что кофе пьют в зелёном доме (4). И не молоко, которое пьют в третьем доме (9). И не апельсиновый сок, потому что человек, который пьёт сок, курит Lucky Strike (13). Следовательно, норвежец пьёт воду, и это ответ на первый вопрос загадки.

Шаг 2

Тогда что же курят во втором, синем доме, где, как мы знаем, держат лошадь?

Это не Kools, который курят в первом доме (8). И не Old Gold, поскольку тот, кто их курит, разводит улиток (7).

Предположим, что в нём курят Lucky Strikes, что означает, что здесь же пьют апельсиновый сок (13). В таком случае, кто может здесь жить? Это не норвежец - он живёт в первом доме (10). Не англичанин - его дом красный (2). Не испанец, поскольку испанец держит собаку (3). Не украинец, потому что украинец пьёт чай (5). И не японец, который курит Parliament (14). Так как данная ситуация невозможна, то во втором доме курят не Lucky Strike.

Предположим, что во втором доме курят Parliament, из чего следует, что здесь живёт японец (14). В таком случае, что он пьёт? Не чай, поскольку чай пьёт украинец (5). Не кофе - кофе пьют в зелёном доме (4). Не молоко - молоко пьют в третьем доме (9). И не сок, потому что сок пьёт человек, который курит Lucky Strike (13). Итак, данная ситуация также невозможна, и во втором доме курят не Parliament.

Следовательно, во втором доме курят Chesterfield .

Какой национальности человек, живущий во втором, синем доме, предпочитающий Chesterfield и держащий лошадь? Это не норвежец - он в первом доме (10). Не англичанин - он в красном доме (2). Не испанец - у испанца собака (3). Не японец - японец курит Parliament (14). Значит, во втором доме живёт украинец и, как следует из (5), пьёт чай!

Шаг 3

Так как Chesterfield курят во втором доме, то из (11) нам становится известно, что лису держат либо в первом, либо в третьем доме.

Давайте сначала предположим, что лиса в третьем доме. В таком случае, что пьёт человек, который курит Old Gold и разводит улиток (7)? Мы уже исключили воду и чай на предыдущих шагах. Он также не может пить сок, поскольку сок пьёт человек, который курит Lucky Strike (13). Молоко тоже не подходит - его пьют в третьем доме (9), где, как мы предположили, держат лису. Остаётся кофе, который, по условию, пьют в зелёном доме (4).

Итак, если в третьем доме держат лису, то в зелёном доме живёт человек, который курит Old Gold, разводит улиток и пьёт кофе,. Кто этот человек? Он не норвежец - норвежец в первом доме (10). Не украинец - тот пьёт чай (5). Не англичанин - тот живёт в красном доме (2). Не японец - он курит Parliament (14). И не испанец - у испанца собака (3).

Такая ситуация невозможна. Из чего следует, что лису держат в первом доме , а не в третьем.

Шаг 4

Из всего вышеизложенного следует, что кофе и апельсиновый сок пьют в четвёртом и пятом доме. Не имеет значения, какой из напитков - в каком доме; будем просто называть их «дом, где пьют сок» и «дом, где пьют кофе».

Итак, где живёт человек, который курит Old Gold и разводит улиток? Не в доме, где пьют сок, потому что там курят Lucky Strike (13).

Предположим, что он живёт в доме, где пьют кофе. Тогда человек, который курит Old Gold, разводит улиток и пьёт кофе, живёт в зелёном (4) доме. Опять же, по тем же соображениям, что и в шаге 3, это невозможно.

Значит, человек, который курит Old Gold и разводит улиток, живёт в третьем доме.

Отсюда следует, что Parliament курят в зелёном доме, где пьют кофе, а живёт там японец (14). Это означает, что испанец - тот, кто пьёт апельсиновый сок, курит Lucky Strikes и держит собаку. Продолжая эти рассуждения, приходим к выводу, что англичанин должен жить в третьем доме, и дом этот - красный. Методом исключения получаем, что дом испанца белый.

Теперь мы заполнили все пробелы, кроме одного, и, очевидно, что зебру держит японец.

Ответ

Замечание

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

Другие формулировки условия задачи

Существует множество различных вариантов условий задачи. В некоторых из них первая посылка оригинального условия оговаривается отдельно или подразумевается неявно, а вместо неё вводится другая, зачастую облегчающая решение задачи. Вместо двух вопросов нередко оставляют один, например, «Кто разводит рыбок?». Иногда вместо марок сигарет указывают средства передвижения или названия растений. Меняются и национальности пяти упоминающихся людей . Например, весьма распространённым в Интернете вариантом является следующий:

На одной улице подряд стоят пять домов, каждый - своего цвета. В каждом живёт человек, все пять - разных национальностей. Каждый человек предпочитает уникальную марку сигарет, напиток и домашнее животное. Кроме того:

  1. Норвежец живёт в первом доме.
  2. Англичанин живёт в красном доме.
  3. Зелёный дом находится слева от белого, рядом с ним.
  4. Датчанин пьёт чай.
  5. Тот, кто курит Marlboro, живёт рядом с тем, кто выращивает кошек.
  6. Тот, кто живёт в жёлтом доме, курит Dunhill.
  7. Немец курит Rothmans.
  8. Тот, кто живёт в центре, пьёт молоко.
  9. Сосед того, кто курит Marlboro, пьёт воду.
  10. Тот, кто курит Pall Mall, выращивает птиц.
  11. Швед выращивает собак.
  12. Норвежец живёт рядом с синим домом.
  13. Тот, кто выращивает лошадей, живёт в синем доме.
  14. Тот, кто курит Winfield, пьет пиво.
  15. В зелёном доме пьют кофе.

Кто разводит рыбок?

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

Решение задачи:

Итак, у нас есть 25 позиций, которые необходимо заполнить следующими данными:

Национальность: Норвежец, Англичанин, Датчанин, Немец, Швед.
Цвет дома: Красный, Зелёный, Белый, Жёлтый, Синий.
Марка сигарет: Ротманс, Данхилл, Мальборо, Пелл Мелл, Филипп Моррис.
Животное: Кошки, Птицы, Собаки, Лошади, Рыбки.
Напиток: Чай, Молоко, Вода, Пиво, Кофе.

По сути, нам надо заполнить вот такую табличку:

Номер дома 1 2 3 4 5
Национальность
Цвет дома
Сигареты
Животное
Напиток

Из подсказок сразу же заполняем ряд ячеек таблицы:

Норвежец живет в первом доме.
Норвежец живет рядом с синим домом.
Тот, кто выращивает лошадей, живет в синем доме.
Тот, кто живет в центре, пьет молоко.
Номер дома 1 2 3 4 5
Национальность Норвежец
Цвет дома Синий
Сигареты
Животное Лошади
Напиток Молоко

Раз англичанин живёт в красном доме, значит, норвежец в красном жить не может. Равно норвежец не может жить в синем. Не может он жить и в белом, так как зелёный дом находится левее белового, а дом норвежца - самый левый. В зелёном он тоже жить не может, так как справа от зелёного белый дом, а справа от норвежца - синий. Значит, он живёт в жёлтом. Отсюда же делаем и вывод, что норвежец курит Данхилл.

Номер дома 1 2 3 4 5
Национальность Норвежец
Цвет дома Жёлтый Синий
Сигареты Данхилл
Животное Лошади
Напиток Молоко

Далее, раз зелёный дом находится левее белого, значит, у него номер либо 3, либо 4. Однако в третьем, среднем, доме пьют молоко, а в зелёном доме пьют кофе - значит номер зелёного дома = 4. Значит, белый дом у нас идёт под номером 5, а красный - под номером 3. Здесь же живёт англичанин. Кофе пьют в 4 доме.

Номер дома 1 2 3 4 5
Национальность Норвежец Англичанин

Сигареты Данхилл
Животное Лошади
Напиток Молоко Кофе

Далее, раз немец курит Мальборо, то он не курит Филипп Моррис, и потому не пьёт пиво. Не пьёт он и молоко, которое пьёт англичанин. Не пьёт и чай - это делает датчанин. Значит, немец пьёт либо воду, либо кофе. Норвежец не может пить пиво (он курит другие сигареты), молоко (не англичанин), кофе (живёт не в зелёном доме), чай (не датчанин). Значит норвежец пьёт воду, а потом немец пьёт кофе, и живёт в зелёном доме. Плюс не забываем, что немец курит Мальборо. И раз воду у нас пьёт норвежец, то его сосед (второй дом) курит Ротманс.

Номер дома 1 2 3 4 5
Национальность Норвежец Англичанин Немец
Цвет дома Жёлтый Синий Красный Зелёный Белый
Животное Лошади
Напиток Вода Молоко Кофе

Раз швед у нас выращивает собак, то он не может жить во втором доме (там выращивают лошадей), значит он живёт в пятом доме (белом). Значит во втором доме живёт датчанин, который пьёт чай.

Номер дома 1 2 3 4 5

Цвет дома Жёлтый Синий Красный Зелёный Белый
Сигареты Данхилл Ротманс Мальборо
Животное Лошади Собаки
Напиток Вода Чай Молоко Кофе

Раз курильщик Пелл Мелл выращивает птиц, то это не швед, а значит - англичанин. Следовательно, швед курит Филипп Моррис и пьёт пиво.

Номер дома 1 2 3 4 5
Национальность Норвежец Датчанин Англичанин Немец Швед
Цвет дома Жёлтый Синий Красный Зелёный Белый

Животное Лошади Птицы Собаки

И теперь у нас осталась последняя подсказка:

Тот, кто курит Rothmans, живет рядом с тем, кто выращивает кошек.
Ротманс курит датчанин, что живёт во втором доме. Справа от него живёт англичанин, который выращивает птиц, значит, второй сосед датчанина (слева), норвежец, этих кошек и выращивает. А потом рыбок выращивает немец. Ответ найден.

Номер дома 1 2 3 4 5
Национальность Норвежец Датчанин Англичанин Немец Швед
Цвет дома Жёлтый Синий Красный Зелёный Белый
Сигареты Данхилл Ротманс Пелл Мелл Мальборо Филипп Моррис
Животное Кошки Лошади Птицы Рыбки Собаки
Напиток Вода Чай Молоко Кофе Пиво

ОТВЕТ: рыбок выращивает немец!

Загадка Эйнштейна – знаменитая , которую составил Альберт Эйнштейн . Кстати, возможно это и не так, но нам не столь важно кто составил эту загадку, важна лишь сама загадка и проверка наших логических способностей . Все таки если придерживаться источников, которые утверждают, что ее составил Эйнштейн, то по ним загадка была придумана им еще в детстве. Многие утверждают, что он составил эту головоломку для отбора кандидатов на должности, которые требуют хорошего логического мышления .

Многие из нас слышали такую фразу о загадке Эйнштейна : “Лишь 2% людей смогут ее решить” . Это не совсем так, вернее это выражение нуждается в дополнении. Может быть и на самом деле лишь пятидесятая часть населения сможет ее решить, но без использования бумаги и ручки (либо вещей, которые их могут заменить). По сути для чистого решения этой задачи у нас в распоряжении должна быть лишь наша память и логика . Если же использовать какие-либо дополнительные способы запоминания (ручка, бумага), то загадка теряет львиную долю сложности – но мне почему то ломать мозг не хочется, поэтому при первом прочтении этой загадки я сразу схватился за листок)

Единой версии загадки Эйнштейна сейчас нет, существует множество ее вариаций. Я приведу в пример самую знаменитую версию Загадки Эйнштейна.

Условия Загадки Эйнштейна.

  • На улице – пять домов .
  • У каждого дома – свой цвет .
  • В каждом доме - живет 1 человек .
  • У каждого человека – своя национальность .
  • Каждый предпочитает курить уникальную марку сигарет, пить свой напиток и содержать животных.

Ну что, со вступлением закончили – теперь перейдем к подсказкам (ну просто офигеть какие простые подсказки )

  1. Норвежец живёт в первом доме.
  2. Англичанин живёт в красном доме.
  3. Зелёный дом находится слева от белого , рядом с ним.
  4. Датчанин пьёт чай .
  5. Тот, кто курит Marlboro , живёт рядом с тем, кто выращивает кошек .
  6. Тот, кто живёт в жёлтом доме, курит Dunhill .
  7. Немец курит Rothmans .
  8. Тот, кто живёт в центре , пьёт молоко .
  9. Сосед того, кто курит Marlboro , пьёт воду .
  10. Тот, кто курит Pall Mall , выращивает птиц .
  11. Швед выращивает собак .
  12. Норвежец живёт рядом с синим домом.
  13. Тот, кто выращивает лошадей , живёт в синем доме.
  14. Тот, кто курит Winfield , пьет пиво .
  15. В зелёном доме пьют кофе .

Вопрос же к загадке Эйнштейна звучит следующим образом: Кто разводит рыбок? Ха! подумаете Вы, ан нет; не все так просто. Пока мы будем определять кто разводит рыбок мы чуть ли не узнаем биографию каждого участника головоломки, и самым последним действием все таки сможем определить кто же все таки этот любитель рыбок . (нет бы сделали вопрос: в каком доме живет Норвежец? (:)

Ну что? собрали волю в кулак, схватили ручку с листочком (или может попробуете в уме?) и вперед: за ответом на загадку Эйнштейна .

Многие сталкивались с головоломкой про пять разноцветных домов, в каждом из которых живет человек со своими любимыми животным, напитком и сигаретами. Эта загадка приписывается Эйнштейну, хотя прямых подтверждений этому нет. Полный текст этой головоломки есть на википедии .

Ее можно решить на бумаге или в уме, последовательно исключая неподходящие варианты. Однако, ее также можно решить более технично. Один из способов - написать программку на прологе. Но здесь я хочу ее решить используя более простые механизмы - регулярные выражения. А именно, перевести условия загадки на язык регекспов и свести задачу к поиску подходящей строки во всем допустимом наборе строк. Кстати, этот набор строк показан на рисунке.

Идея

Сама идея не моя, услышал ее в одной видеолекции. Однако, там ее решали слишком уж изощренно. Я попытался решить ее более просто и прямолинейно.

Для удобства приведу здесь текст загадки:

  1. Норвежец живёт в первом доме.
  2. Англичанин живёт в красном доме.
  3. Зелёный дом находится слева от белого, рядом с ним.
  4. Датчанин пьёт чай
  5. Тот, кто курит Marlboro, живёт рядом с тем, кто выращивает кошек.
  6. Тот, кто живёт в жёлтом доме, курит Dunhill.
  7. Немец курит Rothmans.
  8. Тот, кто живёт в центре, пьёт молоко.
  9. Сосед того, кто курит Marlboro, пьёт воду.
  10. Тот, кто курит Pall Mall, выращивает птиц.
  11. Швед выращивает собак.
  12. Норвежец живёт рядом с синим домом.
  13. Тот, кто выращивает лошадей, живёт в синем доме.
  14. Тот, кто курит Winfield, пьет пиво.
  15. В зелёном доме пьют кофе.
Вопрос: кто разводит рыбок?

Чтобы решить задачу нужно найти такую последовательность домов, цветов, национальностей, напитков и сигарет, чтобы они удовлетворяли правилам выше

И так, что и где мы будем искать. Для начала нужно каким-то образом формализовать правила. У нас пять домов, цветов, национальностей, напитков, животных и сигарет. Произвольный вариант дома с «жильцами» может выглядеть так:

German white cat beer malboro

Но этого недостаточно, так как у нас есть правила, которые учитывают взаимное расположение домов и предметов в них (к примеру, правила: 1, 3, 5...). Учтем это, расположив в строке пять домов последовательно:

German white cat beer malboro englishman red dog water pallmall norwegian green fish milk winfield dane blue bird tea dunhill swede horse yellow coffee rothmans

Строка выше - один из вариантов расположения предметов. В данном случае, неверный. Если же мы составим все возможные варианты, и поместим это в один текст, получится следующее:

N c a d s n c a d s n c a d s n c a d s n c a d s n c a d s n c a d s n c a d s n c a d s n c a d s n c a d s n c a d s n c a d s n c a d s n c a d s ...

Где n - nation, c - color, a - animal, d - drink, s - cigarettes. И каждая из этих букв может принимать одно из пяти своих значений.

Замечательно. То, что остается сделать - перевести правила на язык регулярных выражений:

  1. ^norwegian \w+
  2. \w+ englishman red \w+
  3. \w+ dane \w \w tea \w+
И если строка подойдет ко всем правилам, то мы нашли решение! Останется только посмотреть национальность в доме с рыбой. Это и является главной идеей поиска: построить текст и пройтись по нему регулярными выражениями.

Но есть плохая новость. Текст, по которому будет проходить поиск может быть ОЧЕНЬ большим. Если точнее, он будет размером (5!)^5 строк (~24 миллиардов). Его не то чтобы проверить, его будет сложно даже сгенерировать. Но есть и хорошая новость. Мы можем не генерировать весь этот текст, а воспользоваться операцией пересечения регулярных выражений. То есть найдем все общие строки регулярного выражения * (все возможные строки), с теми строками, которые дают регулярные выражения правил задачи . Та строка (а может и строки) что останется после пересечения и будет решением задачи.

К сожалению я не знаю движков, способных пересекать регулярные выражения. По этому придется использовать напрямую конечные автоматы, лежащие в основе любого регекспа.

Реализация

Конечные автоматы буду строить с помощью библиотечки openfst . Она дает все что мне необходимо для построения автоматов, плюс удобный способ работы из шелла. Чтобы сделать программирование еще более «ненормальным», я вообще не буду программировать:). За исключением простых bash-скриптов кода не будет.

Шаг 1 - Строим базовые автоматы

Создадим текстовый файл со списком всех объектов. Это будет наш алфавит.
norwegian englishman dane german swede white red ...

Построим базовые автоматы, каждый из которых допускает только одно слово из алфавита.
j=1 for i in `cat alph`; do echo -e "0 1 $j\n1" | fstcompile --acceptor > $i ((j=$j+1)) done

Fstcompile - команда пакета openfst, компилирующая текстовое представление автомата в бинарное. Это нужно для того, чтобы потом применять к этому автомату различные операции.

И так, у нас появился список файлов-автоматов. Они очень тривиальны. К примеру, автомат beer будет выглядить так:

Он эквивалентен регулярному выражению «beer». Пока все довольно просто. Кроме того нам понадобятся еще два базовых автомата - пустое множество, и любая строка, т.е. звездочка *. Строим.

Шаг 2 - Строим пустой автомат и звездочку

Пустая строка, автомат "empty":
echo "0" | fstcompile --acceptor > empty

Звездочка, автомат "star":
cp empty star for i in `cat alph`; do fstunion star $i star done fstclosure star star
Последний делается простым объединением базовых автоматов и замыканием. В регулярных выражениях это всего лишь (englishman|dane|...|cat|dog|...)*. Этот автомат будет таким:

Шаг 3 - Строим дома

Правила будет удобней описывать, если создать более комплексные автоматы, такие как национальность, цвет и т.д. Опять, использую несложный скрипт:

C="./concat.sh" $c norwegian star > r1 $c star englishman red star > r2 $c star animal drink cigarette nation star > r3 $c star dane color animal tea star > r4 $c star malboro nation color cat star > r5_0 $c star cat drink cigarette nation color animal drink malboro star > r5_1 $c star yellow animal drink dunhill star > r6 $c star german color animal drink rothmans > r7 $c house house nation color animal milk cigarette house house > r8 $c star malboro nation color animal water star > r9_0 $c star water cigarette nation color animal drink malboro star > r9_1 $c star bird drink pallmall star > r10 $c star swede color dog star > r11 $c star norwegian color animal drink cigarette nation blue star > r12_0 $c star blue animal drink cigarette norwegian star > r12_1 $c star blue horse star > r13 $c star beer winfield star > r14 $c star green animal coffee star > r15 fstunion r5_0 r5_1 > r5 fstunion r9_0 r9_1 > r9 fstunion r12_0 r12_1 > r12

Правила 5, 9 и 12 являются составными. Я определяю каждую часть отдельно, а потом делаю объединение. Скрипт concat.sh всего лишь делает конкатинацию автоматов, переданных в аргументах:
cp empty _c for i in $*; do fstconcat _c $i _c done; cat _c; rm _c;

Итак, на выходе получим автоматы r1,r2...,r15. Все готово для финального шага.

Шаг последний - Пересечение

./intersect.sh r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15 > result

Где intersect.sh - пересечение автоматов в аргументах.
cp cl _c for i in $*; do fstintersect _c $i _c done; cat _c; rm _c;

На этом можно было бы и закончить - посмотреть автомат и узнать у кого рыба. Но я с самого начала не учел одну вещь - в моих правилах каждое из слов может повторятся. К примеру, два человека могут пить одно пиво и заводить одно животное. Это неверно по условиям задачи. Создавать такой фильтр крайне неудобно, используя регулярные языки, т.к. у нас нет способа «запомнить», что такое слово уже было. Но ограничить как-то нужно. По этому подвергаем финальный результат следующему скрипту.

I="./intersect.sh" d="fstdifference" for i in `cat alph`; do fstdifference cl $i > differ fstconcat differ $i | fstconcat - differ | fstrmepsilon - | fstdeterminize - | fstminimize - > ${i}_cont done cp result out for i in `ls *_cont`; do echo $i fstintersect $i out | fstrmepsilon - | fstdeterminize - | fstminimize - out done rm differ rm *_cont

Этот скрипт формирует специальный авотомат для каждого слова из алфавита, и применяет его к результату. Таким образом, отметаются пути с повторяющимися словами. В итоге, финальный результат (а по сути, автомат "out") выглядит так:

Это частичное изображение автомата (все не влезло). Каждые пять слов определяют дом. Как видно из рисунка, немец разводит рыбок.

Заключение

Вот такой вот необычный способ решения задачи. Но кроме всего прочего он показывает, что регулярные языки - это довольно мощная штука. Более того, если верить Ульману, любую математическую проблему можно представить как нахождения строки в определенном языке . Что и было показано.

Ps и да, мьсе действительно знает толк в извращениях:)