17 svar
377 visningar
MrPotatohead behöver inte mer hjälp

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:

:)

sictransit Online 2844 – Livehjälpare
Postad: 26 jul 19:06 Redigerad: 26 jul 19:09

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.😜

Trinity2 Online 3710
Postad: 27 jul 19:55

Einstein's Riddle

Som 98% inte klarar... ;)

Trinity2 Online 3710
Postad: 27 jul 20:33
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.

Trinity2 Online 3710
Postad: 27 jul 21:48

En snillrik metod att få klick = pengar.

Man ser det överallt idag.

Jag bara skojade. Det var taget från en clickbait-titel.✌️

Laguna 31739
Postad: 28 jul 14:38

Hur många klarar det om påstående 15 inte är med?

Hmm, trodde allt behövdes. Kanske inte hardcore-varianten detta.

sictransit Online 2844 – Livehjälpare
Postad: 28 jul 15:58 Redigerad: 28 jul 16:05
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.

Louis 3896
Postad: 29 jul 20:50

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. 

MrPotatohead 8003 – Moderator
Postad: 30 jul 22:58 Redigerad: 30 jul 22:58
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. 

Svara
Close