Sommarkluring: Vem äger fisken?
En klassiker som är väldigt värd att prova för den som inte testat. Frågeställningen är följande
There are five houses of five different colors. In each house lives a person of a different nationality. Each of these five men drinks a certain beverage, smokes a certain brand of cigarettes, and keeps a certain pet. No two men have the same pet, drink the same drink or smoke the same brand. We also know the following:
1. The Brit lives in the red house.
2. The Swede keeps a dog.
3. The Dane drinks tea.
4. The green house is on the left of the white house.
5. The owner of the green house drinks coffee.
6. The person who smokes Pall Mall rears birds.
7. The owner of the yellow house smokes Dunhill.
8. The man living in the house right in the center drinks milk.
9. The Norwegian lives in the first house.
10. The man who smokes Blend lives next to the one who has cats.
11. The man who has horses lives next to the Dunhill smoker.
12. The man who smokes Bluemaster drinks beer.
13. The German smokes Princess.
14. The Norwegian lives next to the blue house.
15. The man who smokes Blend has a neighbor who drinks water.
Determine who owns the fish.
Ge ditt svar i en spoiler enligt nedan
Svar:
:)
Sådana här uppgifter lämpar sig alldeles utmärkt för villkorsprogrammering. Du deklarerar villkoren och efterfrågar sedan möjliga lösningar. Jag har fastnat för MiniZinc, men det finns förstås andra språk.
Det är knappast en spoiler om jag klipper in lite kod:
include "alldifferent.mzn";
enum Nationalities={Brit, Swede, Dane, Norwegian, German};
enum Drinks={tea, coffee, milk, beer, water};
enum Pets={dog, birds, cats, horses, fish};
enum Colours={red, green, white, yellow, blue};
enum Smokes={PallMall, Dunhill, Blend, Bluemaster, Princess};
% There are five houses.
set of int: HOUSES = 1..5;
array[HOUSES] of var Nationalities: Nh; constraint alldifferent(Nh);
array[HOUSES] of var Drinks: Dh; constraint alldifferent(Dh);
array[HOUSES] of var Pets: Ph; constraint alldifferent(Ph);
array[HOUSES] of var Colours: Ch; constraint alldifferent(Ch);
array[HOUSES] of var Smokes: Sh; constraint alldifferent(Sh);
% 1. The Brit lives in the red house.
constraint exists(h in HOUSES)(Nh[h]=Brit /\ Ch[h]=red);
% 2. The Swede keeps a dog.
constraint exists(h in HOUSES)(Nh[h]=Swede /\ Ph[h]=dog);
% 3. The Dane drinks tea.
constraint exists(h in HOUSES)(Nh[h]=Dane /\ Dh[h]=tea);
% 4. The green house is on the left of the white house.
constraint exists(h in 1..4)(Ch[h]=green /\ Ch[h+1]=white);
% 5. The owner of the green house drinks coffee.
constraint exists(h in HOUSES)(Ch[h]=green /\ Dh[h]=coffee);
% 6. The person who smokes Pall Mall rears birds.
constraint exists(h in HOUSES)(Sh[h]=PallMall /\ Ph[h]=birds);
% 7. The owner of the yellow house smokes Dunhill.
constraint exists(h in HOUSES)(Ch[h]=yellow /\ Sh[h]=Dunhill);
% 8. The man living in the house right in the center drinks milk.
constraint Dh[3]=milk;
% 9. The Norwegian lives in the first house.
constraint Nh[1]=Norwegian;
% 10. The man who smokes Blend lives next to the one who has cats.
constraint exists(h in 1..4)(Sh[h]=Blend /\ Ph[h+1]=cats \/ Sh[h+1]=Blend /\ Ph[h]=cats);
% 11. The man who has horses lives next to the Dunhill smoker.
constraint exists(h in 1..4)(Ph[h+1]=horses /\ Sh[h]=Dunhill \/ Ph[h]=horses /\ Sh[h+1]=Dunhill);
% 12. The man who smokes Bluemaster drinks beer.
constraint exists(h in HOUSES)(Sh[h]=Bluemaster /\ Dh[h]=beer);
% 13. The German smokes Princess.
constraint exists(h in HOUSES)(Nh[h]=German /\ Sh[h]=Princess);
% 14. The Norwegian lives next to the blue house.
constraint exists(h in 1..4)(Nh[h]=Norwegian /\ Ch[h+1]=blue \/ Nh[h+1]=Norwegian /\ Ch[h]=blue);
% 15. The man who smokes Blend has a neighbor who drinks water.
constraint exists(h in 1..4)(Sh[h]=Blend /\ Dh[h+1]=water \/ Sh[h+1]=Blend /\ Dh[h]=water);
% Determine who owns the fish.
var 1..5: hFish;
constraint Ph[hFish]=fish;
solve satisfy;
output ["The "++show(Nh[hFish])++" owns the fish."];
Kör man detta trillar följande ut:
Visa spoiler
Running pluggakuten.mzn
The German owns the fish.
----------
==========
Finished in 143msec.
Den dubbla understrykningen visar att det är samtliga lösningar som visas. I vissa lägen kan det ju vara tillräckligt (eller nödvändigt) att nöja sig med första bästa. Typ: lös "x+y=42".
Det som är klurigt i just den här varianten av problemet är tolkningen av predikat #4.
Att det gröna huset står till vänster om det vita är givet, men står det omedelbart till vänster om det?
Om man tillåter att det står någonstans till vänster finns det inte längre en enda unik lösning:
Running pluggakuten.mzn
The German owns the fish.
----------
The Dane owns the fish.
----------
The Norwegian owns the fish.
----------
==========
Finished in 143msec.
Ha en fortsatt trevlig sommar alla!
Tillägg: 27 jul 2025 10:26
När man väl har koden kan man roa sig med att ta bort predikat. Då upptäcker man att #15 vare sig gör till eller från. Tillräcklig information finns utan detta.
Ååå vilken kul lösning!🥹🥰 Ska testa i Python senare.😜
Einstein's Riddle
Som 98% inte klarar... ;)
MrPotatohead skrev:Som 98% inte klarar... ;)
Är statistiken så illa?
Trinity2 skrev:MrPotatohead skrev:Som 98% inte klarar... ;)
Är statistiken så illa?
Tror jag inte. Det känns som alla ”98% klarar inte det här” på typ Facebook. Visa belagda siffror annars avfärdar jag det som ”meme”.
sictransit skrev:Trinity2 skrev:MrPotatohead skrev:Som 98% inte klarar... ;)
Är statistiken så illa?
Tror jag inte. Det känns som alla ”98% klarar inte det här” på typ Facebook.

En snillrik metod att få klick = pengar.
Man ser det överallt idag.
Jag bara skojade. Det var taget från en clickbait-titel.✌️
Hur många klarar det om påstående 15 inte är med?
Hmm, trodde allt behövdes. Kanske inte hardcore-varianten detta.
MrPotatohead skrev:Hmm, trodde allt behövdes. Kanske inte hardcore-varianten detta.
Min kod och MiniZinc säger att #15 inte behövs. Jag har inte försökt lösa med penna/papper/hjärna.
Blend finns ju definierat, men däremot inte water. Utan att analysera allt så kan jag gissa att de övriga fyra dryckerna är satta redan, samt att water redan är fixerat givet övriga.
#15 är dock det enda man kan stryka utan att få fler än en möjlig lösning.
Då ska jag testa på den varianten istället.💪
MrPotatohead skrev:Då ska jag testa på den varianten istället.💪
Lycka till! Det finns säkert bra bibliotek i python. Posta gärna lite kod.
Inte så mycket svårare utan #15. Men tråkigare. Vid en punkt måste man där två hus kan komma ifråga gissa på det ena och följa det spåret ända tills man är framme vid en motsägelse. Sådant behövs inte med #15.
Själv fastnade jag (med #15) efter att husfärgerna och sex andra bestämningar var gjorda (jag tillhör alltså de 98%). Fick glutta på YouTube. Knepet var att inte fortsätta att använda ledtrådarna direkt utan i stället ställa en fråga:
Visa spoiler
Vad dricker norrmannen?
Minns när jag stötte på denna för första gången i årskurs 7.
Visa spoiler
Tipset att skriva upp allt i en tabell var minst sagt revolutionerande.
Tillägg: 29 jul 2025 22:05
Håller på med koden nu. Det var inte den finurligaste koden jag skrivit, kanske för att jag råka ta för mycket starthjälp.
from z3 import *
s = Solver()
N = 5
# Define houses with properties
nationalities = [Int(f'nat_{i}') for i in range(N)]
drinks = [Int(f'dri_{i}') for i in range(N)]
colors = [Int(f'col_{i}') for i in range(N)]
smokes = [Int(f'smo_{i}') for i in range(N)]
pets = [Int(f'pet_{i}') for i in range(N)]
NAT = {"German": 0, "Swede": 1, "Dane": 2, "Norwegian": 3, "Brit": 4}
DRI={"tea": 0, "coffee": 1, "milk": 2, "beer": 3, "water": 4}
PET={"dog": 0, "birds": 1, "cats": 2, "horses": 3, "fish": 4}
COL={"red": 0, "green": 1, "white": 2, "yellow": 3, "blue": 4}
SMO={"PallMall": 0, "Dunhill": 1, "Blend": 2, "Bluemaster": 3, "Princess": 4}
#Constraints:
#1. The Brit lives in the red house.
s.add(Or([And(NAT["Brit"]==nationalities[i], COL["red"]==colors[i]) for i in range(N)]))
#2. The Swede keeps a dog.
s.add(Or([And(PET["dog"]==pets[i], NAT["Swede"]==nationalities[i]) for i in range(N)]))
#3. The Dane drinks tea.
s.add(Or([And(DRI["tea"]==drinks[i], NAT["Dane"]==nationalities[i]) for i in range(N)]))
#4. The green house is on the left of the white house.
s.add(Or([And(COL["green"]==colors[i], COL["white"]==colors[j], j-i==1) for i in range(N) for j in range(N) if i != j]))
#5. The owner of the green house drinks coffee.
s.add(Or([And(COL["green"]==colors[i], DRI["coffee"]==drinks[i]) for i in range(N)]))
#6. The person who smokes Pall Mall rears birds.
s.add(Or([And(PET["birds"]==pets[i], SMO["PallMall"]==smokes[i]) for i in range(N)]))
#7. The owner of the yellow house smokes Dunhill.
s.add(Or([And(COL["yellow"]==colors[i], SMO["Dunhill"]==smokes[i]) for i in range(N)]))
#8. The man living in the house right in the center drinks milk.
s.add(DRI["milk"]==drinks[2])
#9. The Norwegian lives in the first house.
s.add(NAT["Norwegian"]==nationalities[0])
#10. The man who smokes Blend lives next to the one who has cats.
s.add(Or([And(PET["cats"]==pets[i], SMO["Blend"]==smokes[j], Abs(i-j)==1) for i in range(N) for j in range(N) if i != j]))
#11. The man who has horses lives next to the Dunhill smoker.
s.add(Or([And(PET["horses"]==pets[i], SMO["Dunhill"]==smokes[j], Abs(i-j)==1) for i in range(N) for j in range(N) if i != j]))
#12. The man who smokes Bluemaster drinks beer.
s.add(Or([And(DRI["beer"]==drinks[i], SMO["Bluemaster"]==smokes[i]) for i in range(N)]))
#13. The German smokes Princess.
s.add(Or([And(SMO["Princess"]==smokes[i], NAT["German"]==nationalities[i]) for i in range(N)]))
#14. The Norwegian lives next to the blue house.
s.add(Or([And(COL["blue"]==colors[i], NAT["Norwegian"]==nationalities[j], Abs(i-j)==1) for i in range(N) for j in range(N) if i != j]))
#15. The man who smokes Blend has a neighbor who drinks water. (VALFRI)
s.add(Distinct(colors))
s.add(Distinct(pets))
s.add(Distinct(nationalities))
s.add(Distinct(smokes))
s.add(Distinct(drinks))
if s.check() == sat:
m = s.model()
fish_index = None
for i in range(N):
if m.evaluate(pets[i]).as_long() == PET["fish"]:
fish_index = i
break
if fish_index is not None:
fish_owner_id = m.evaluate(nationalities[fish_index]).as_long()
for name, code in NAT.items():
if code == fish_owner_id:
print(f"Det är tydligen {name}en som har fisken. (Hus {fish_index + 1})")
#Output: Det är tydligen Germanen som har fisken. (Hus 4)
Det var jobbigt.