Загадка эйнштейна про рыбок

Обновлено: 24.12.2024

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

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

  • member(Elem, List) — истина, если элемент Elem есть в списке List
  • nth1(N, List, Elem) — истина, если элемент Elem в списке List стоит на N-й (счет начинается с 1) позиции
  • nextto(X, Y, List) — истина, если X стоит перед (слева от) Y в списке List
neighbors ( X , Y , List ) :- nextto ( X , Y , List ) .
neighbors ( X , Y , List ) :- nextto ( Y , X , List ) .

Т.е., либо X слева от Y, либо наоборот.

А вот, собственно, и решение:

einstein :-
/* 0. Всего 5 домов */
Houses = [ _ , _ , _ , _ , _ ] ,
/* 1. Норвежец живёт в первом доме. */
nth1 ( 1 , Houses , [ norwegian , _ , _ , _ , _ ] ) ,
/* 2. Англичанин живёт в красном доме. */
member ( [ englishman , _ , _ , _ , red ] , Houses ) ,
/* 3. Зелёный дом находится слева от белого, рядом с ним. */
nextto ( [ _ , _ , _ , _ , green ] , [ _ , _ , _ , _ , white ] , Houses ) ,
/* 4. Датчанин пьёт чай. */
member ( [ dane , _ , _ , tea , _ ] , Houses ) ,
/* 5. Тот, кто курит Marlboro, живёт рядом с тем, кто выращивает кошек. */
neighbors ( [ _ , _ , marlboro , _ , _ ] , [ _ , cat , _ , _ , _ ] , Houses ) ,
/* 6. Тот, кто живёт в жёлтом доме, курит Dunhill. */
member ( [ _ , _ , dunhill , _ , yellow ] , Houses ) ,
/* 7. Немец курит Rothmans. */
member ( [ german , _ , rothmans , _ , _ ] , Houses ) ,
/* 8. Тот, кто живёт в центре, пьёт молоко. */
nth1 ( 3 , Houses , [ _ , _ , _ , milk , _ ] ) ,
/* 9. Сосед того, кто курит Marlboro, пьёт воду. */
neighbors ( [ _ , _ , marlboro , _ , _ ] , [ _ , _ , _ , water , _ ] , Houses ) ,
/* 10. Тот, кто курит Pall Mall, выращивает птиц. */
member ( [ _ , bird , pallmall , _ , _ ] , Houses ) ,
/* 11. Швед выращивает собак. */
member ( [ swede , dog , _ , _ , _ ] , Houses ) ,
/* 12. Норвежец живёт рядом с синим домом. */
neighbors ( [ norwegian , _ , _ , _ , _ ] , [ _ , _ , _ , _ , blue ] , Houses ) ,
/* 13. Тот, кто выращивает лошадей, живёт в синем доме. */
member ( [ _ , horse , _ , _ , blue ] , Houses ) ,
/* 14. Тот, кто курит Winfield, пьет пиво. */
member ( [ _ , _ , winfield , beer , _ ] , Houses ) ,
/* 15. В зелёном доме пьют кофе. */
member ( [ _ , _ , _ , coffee , green ] , Houses ) ,

/* Внимание, вопрос: у кого рыба? */
member ( [ Owner , fish , _ , _ , _ ] , Houses ) ,

/* Печатаем решение */
print ( 'Owner of the fish: ' ) , print ( Owner ) , nl ,
print ( 'Full Solution: ' ) , print ( Houses ) , nl .

Как видим, суммарное количество строк в программе практически совпадает с количеством условий в оригинальной задаче.
Да и сами строчки читаются почти как оригинальные условия. Пролог — очень декларативный язык, нам лишь нужно описать что мы от него хотим.
Интерпретатор выполняет за нас всю грязную работу, причем достаточно быстро. На моей машине скрипт выполняется за 0.08сек, если скомпилировать то будет еще немного быстрее.

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

member ( X , [ X | _]).
member ( X , [_ | Rest ]) :- member ( X , Rest ).

nth1 ( 1 , [ Elem | _], Elem ).
nth1 ( N , [_ | Rest ], Elem ) :- N > 1 , K is N - 1 , nth1 ( K , Rest , Elem ).

nextto ( L , R , [ L , R | _]).
nextto ( L , R , [_ | Rest ]) :- nextto ( L , R , Rest ).

Следующая загадка

Была такая компьютерная игра Sherlok. Как раз с такими загадками. Очень много времени я за ней проводил. В итоге наловчился решать такие задачки за минуту, а то и быстрее. :)
Норвежец пьет воду. У японца зебра. :)

Ответить • Ссылка • Пожаловаться •

Ссылка youtu.be

Ответить • Ссылка • Пожаловаться •

Klement Piyat гуру --> 6 лет назад

Судебная медицинская комиссия, которая должна была установить, может ли Швейк, имея в виду его психическое состояние, нести ответственность за все те преступления, в которых он обвиняется, состояла из трех необычайно серьезных господ, причем взгляды одного совершенно расходились со взглядами двух других. Здесь были представлены три разные школы психиатров.
И если в случае со Швейком три противоположных научных лагеря пришли к полному соглашению, то это следует объяснить единственно тем огромным впечатлением, которое произвел Швейк на всю комиссию, когда, войдя в зал, где должно было происходить исследование его психического состояния, и заметив на стене портрет австрийского императора, громко воскликнул: "Господа, да здравствует государь император Франц-Иосиф Первый!"
Дело было совершенно ясно. Благодаря сделанному Швейком, по собственному почину, заявлению целый ряд вопросов отпал и осталось только несколько важнейших. Ответы на них должны были подтвердить первоначальное мнение о Швейке, составленное на основе системы доктора психиатрии Кадлерсона, доктора Гевероха и англичанина Вейкинга.
— Радий тяжелее олова?
— Я его, извиняюсь, не вешал,— со своей милой улыбкой ответил Швейк.
— Вы верите в конец света?
— Прежде я должен увидеть этот конец. Но, во всяком случае, завтра его еще не будет,— небрежно бросил Швейк.
— А вы могли бы вычислить диаметр земного шара?
— Извиняюсь, не смог бы,— сказал Швейк.— Однако мне тоже хочется, господа, задать вам одну загадку,— продолжал он.— Стоит четырехэтажный дом, в каждом этаже по восьми окон, на крыше — два слуховых окна и две трубы, в каждом этаже по два квартиранта. А теперь скажите, господа, в каком году умерла у швейцара бабушка?
Судебные врачи многозначительно переглянулись. Тем не менее один из них задал еще такой вопрос:
— Не знаете ли вы, какова наибольшая глубина в Тихом океане?
— Этого, извините, не знаю,— послышался ответ,— но думаю, что там наверняка будет глубже, чем под Вышеградской скалой на Влтаве.
— Достаточно? — лаконически спросил председатель комиссии.
Но один из членов попросил разрешения задать еще один вопрос:
— Сколько будет, если умножить двенадцать тысяч восемьсот девяносто семь на тринадцать тысяч восемьсот шестьдесят три?
— Семьсот двадцать девять,— не моргнув глазом, ответил Швейк.
— Я думаю, вполне достаточно,— сказал председатель комиссии. — Можете отвести обвиняемого на прежнее место.
— Благодарю вас, господа,— вежливо сказал Швейк,— с меня тоже вполне достаточно.

Ответить • Ссылка • Пожаловаться •

Бахтиер Базаров гуру --> 6 лет назад

блин не дописал 5ый дом зеленый:)

Ответить • Ссылка • Пожаловаться •

Бахтиер Базаров гуру --> 6 лет назад

1ый дом желтый норвежец вода курит кул лиса
2ой дом синий укр чай честер лошадь
3ий дом красный англичанин молоко олдголд улитка
4ый дом белый испанец апсок лакистрайк собака
5ый дом японец кофе парламент зебра

Ответить • Ссылка • Пожаловаться •

Rgeroy гуру --> Бахтиер Базаров 6 лет назад

небольшая поправка.
первые три у меня совпали, если учитывать, что счет идет справа налево.
4-й дом не может быть белым, т.к. зеленый дом стоит справа от белого. а справа у тебя будет красный.
У меня 4-й Японец-зеленый-кофе-парламент-зебра.
5-й Испанец-белый-ап.сок-лаки страйк- собака.

Ответить • Ссылка • Пожаловаться •

Бахтиер Базаров гуру --> Rgeroy 6 лет назад

сразу справа от белого это значит после белого, смотри сноску на шестое условие.

Ответить • Ссылка • Пожаловаться •

Rgeroy гуру --> Бахтиер Базаров 6 лет назад

Ещё одно замечание: в утверждении 6 справа означает справа относительно Вас."

Ответить • Ссылка • Пожаловаться •

Александр Оленев гуру --> 6 лет назад

баян с бородой

Ответить • Ссылка • Пожаловаться •

Ветал гуру --> 6 лет назад

Плюсую за ПС ))

Ответить • Ссылка • Пожаловаться •

Константин гуру --> 6 лет назад

Удача нужна слабым! А мне просто некогда фигнёй маяться

Ответить • Ссылка • Пожаловаться •

АндрейЩабленко гуру --> 6 лет назад

- Извиняюсь, не смог бы,-- сказал Швейк.-- Однако мне тоже хочется, господа, задать вам одну загадку,-- продолжал он.-- Стоит четырехэтажный дом, в каждом этаже по восьми окон, на крыше - два слуховых окна и две трубы, в каждом этаже по два квартиранта. А теперь скажите, господа, в каком году умерла у швейцара бабушка? © Я. Гашек

Ответить • Ссылка • Пожаловаться •

MihailoSerbiya гуру --> 6 лет назад

Eto novii vid reklami kureniya ?

Ответить • Ссылка • Пожаловаться •

Homer гуру --> 6 лет назад

5. Украинец пьёт чай. Нереальное условие. Задача, соответственно, нерешаема. Ни устно, ни письменно.

Ответить • Ссылка • Пожаловаться •

Роман гуру --> 6 лет назад

Ничего сложного,очень давно я разгадал эту загадку меньше чем за час,хотя данные были чуть другие. )))

Ответить • Ссылка • Пожаловаться •

Xaoc гуру --> 6 лет назад

как же вы надоели этой задачкой типа эйшейнамля

Ответить • Ссылка • Пожаловаться •

Максим гуру --> 6 лет назад

Ответить • Ссылка • Пожаловаться •

Причем тут сила выталкивания? Пинг-понг закреплен к дну сосуда.
Если ты едешь в лифте и зацепившись за потолок кабинки станешь подтягиваться, лифт от этого станет легче?

Ответить • Ссылка • Пожаловаться •

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

Следующая загадка

Как кричит олень

В Америке арестовали парня после неудачного объявления о продаже катализатора

Loading.

Полицейский не стал церемониться с защищающей подругу девушкой

В Петербурге блогершу чуть не зарезали из-за доставленной не по адресу пиццы

Привинтили на славу: автомобильные номера

Почему у Швейцарии и Науру нет столицы?

34 книги для дизайнеров

Вещицы, сделанные своими руками, которыми не грех и похвастаться

Терри Фокс: «когда-нибудь боль должна сдаться»

8 книг, которые помогут примириться со смертью

Белка устроила склад орехов под капотом внедорожника

Как ловили банду эвенка Павлова, грабившего золотые прииски

Детки в печке: удивительные русские традиции

Функции зеленого покрова деревьев

В Турции археологи нашли скульптуры возрастом 11 тысяч лет

20 фотографий, для полного понимания которых понадобится "звонок другу"

Студент МАДИ передает привет советскому наследию

"Молчание ягнят" - как создавался один из лучших триллеров в истории кино?

10 полезных книг для владельцев собак

Популярные наручные часы в СССР

Авария дня. Момент смертельного ДТП с мотоциклистом в Твери

Chevrolet Corvette AAT Commemorative Edition 1953/2003 — особый подарок к 50-летию Corvette

12 книг, которые должен прочесть каждый родитель

"Охотники за привидениями": интересные факты о фильме и фото со съёмок

Угадайте фильм ужасов по одному кадру

Почему в СССР Зеркала вешали таким образом?

Ассенизатор устроил шоу с канализационным люком на дороге

"Доступное жильё": опасные для жизни дома в поселке под Краснодаром

«Убийственно красива»: британец влюбился в девушку из рекламы и нашел ее, чтобы жениться

Курица удивила петуха необычными детенышами

Жуткие косметические резиновые маски 1910-х годов

Электрокар Tesla Model S сгорел прямо на парковке сервисного центра

На Канарах бушует вулкан

8 книг о школьной жизни, которые понравятся современным детям

У советских детей были такие интересные игрушки

Забавные демотиваторы на разные темы

Модные тренды: уйти или остаться?

Эта суперяхта с ядерной силовой установкой выйдет в море, чтобы бороться с изменением климата

Следующая загадка


Не так давно я прочитал на Хабре статью, которая напомнила мне про интересную головоломку, которую называют «Загадкой Эйнштейна» или «Zebra puzzle». Вероятно многие из вас решали эту задачку на листке бумаги и гордились тем, что входят в несколько процентов населения земли, способных на это.

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

Алгоритм
  • существует упорядоченный набор объектов (в условии их пять и это дома на одной улице);
  • каждый объект обладает набором атрибутов, которые в свою очередь могут принимать фиксированный набор значений (в условии таких атрибутов так же пять: национальность владельца, цвет дома, домашнее животное, любимый напиток и марка сигарет владельца);
  • значения атрибутов не могут совпадать у разных объектов и количество значений каждого атрибута равно соответственно количеству объектов.
  • Кроме того дан ряд ограничений (15), которые описывают сочетания значений атрибутов (полный текст условия можно прочитать по одной из ссылок в начале статьи).

Первой мыслью был полный перебор вариантов с проверкой выполнения условий задачи, но несложные подсчеты показывают, что количество комбинаций равно
5! 5 = 24.883.200.000 , что довольно много.

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

Следующим шагом было решение описывать подмножества решений в виде набора шаблонов: решений, в которых некоторые атрибуты некоторых объектов фиксированы, а остальные могут принимать любые допустимые значения. А имея такое описание нужно только научиться делать пересечение множеств, описанных таким образом.

Решение

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

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

Впрочем, читайте сами — я оставил для вас немало комментариев.
Но и вашим комментариям я буду рад.

Читайте также: