Pary dat. Rozwiązanie zagadki kalendarzowej

https://xpil.eu/ywu

Zagadka jest całkiem prosta i da się ją - przy odrobinie cierpliwości - rozwiązać bez pomocy komputerów. Ja - z braku cierpliwości - napisałem sobie oczywiście prosty skrypt w Pythonie:

import pandas as pd
from pprint import pprint

dates = pd.date_range(start="2023-01-01", end="2023-12-31")
solution = set()

for d1 in dates:
    for d2 in dates:
        if (sorted([d1.month, d1.day]) == sorted([d2.month+d2.day, d2.month*d2.day])):
            solution.add(((d2.month, d2.day), (d1.month, d1.day)))
pprint(solution)
print(len(solution))

Wynik:

{((1, 1), (1, 2)),   
 ((1, 1), (2, 1)),   
 ((1, 2), (2, 3)),   
 ((1, 2), (3, 2)),   
 ((1, 3), (3, 4)),   
 ((1, 3), (4, 3)),   
 ((1, 4), (4, 5)),   
 ((1, 4), (5, 4)),   
 ((1, 5), (5, 6)),   
 ((1, 5), (6, 5)),   
 ((1, 6), (6, 7)),   
 ((1, 6), (7, 6)),   
 ((1, 7), (7, 8)),   
 ((1, 7), (8, 7)),   
 ((1, 8), (8, 9)),   
 ((1, 8), (9, 8)),   
 ((1, 9), (9, 10)),  
 ((1, 9), (10, 9)),  
 ((1, 10), (10, 11)),
 ((1, 10), (11, 10)),
 ((1, 11), (11, 12)),
 ((1, 11), (12, 11)),
 ((1, 12), (12, 13)),
 ((2, 1), (2, 3)),   
 ((2, 1), (3, 2)),   
 ((2, 2), (4, 4)),   
 ((2, 3), (5, 6)),   
 ((2, 3), (6, 5)),   
 ((2, 4), (6, 8)),   
 ((2, 4), (8, 6)),   
 ((2, 5), (7, 10)),  
 ((2, 5), (10, 7)),
 ((2, 6), (8, 12)),
 ((2, 6), (12, 8)),
 ((2, 7), (9, 14)),
 ((2, 8), (10, 16)),
 ((2, 9), (11, 18)),
 ((2, 10), (12, 20)),
 ((3, 1), (3, 4)),
 ((3, 1), (4, 3)),
 ((3, 2), (5, 6)),
 ((3, 2), (6, 5)),
 ((3, 3), (6, 9)),
 ((3, 3), (9, 6)),
 ((3, 4), (7, 12)),
 ((3, 4), (12, 7)),
 ((3, 5), (8, 15)),
 ((3, 6), (9, 18)),
 ((3, 7), (10, 21)),
 ((3, 8), (11, 24)),
 ((3, 9), (12, 27)),
 ((4, 1), (4, 5)),
 ((4, 1), (5, 4)),
 ((4, 2), (6, 8)),
 ((4, 2), (8, 6)),
 ((4, 3), (7, 12)),
 ((4, 3), (12, 7)),
 ((4, 4), (8, 16)),
 ((4, 5), (9, 20)),
 ((4, 6), (10, 24)),
 ((4, 7), (11, 28)),
 ((5, 1), (5, 6)),
 ((5, 1), (6, 5)),
 ((5, 2), (7, 10)),
 ((5, 2), (10, 7)),
 ((5, 3), (8, 15)),
 ((5, 4), (9, 20)),
 ((5, 5), (10, 25)),
 ((5, 6), (11, 30)),
 ((6, 1), (6, 7)),
 ((6, 1), (7, 6)),
 ((6, 2), (8, 12)),
 ((6, 2), (12, 8)),
 ((6, 3), (9, 18)),
 ((6, 4), (10, 24)),
 ((6, 5), (11, 30)),
 ((7, 1), (7, 8)),
 ((7, 1), (8, 7)),
 ((7, 2), (9, 14)),
 ((7, 3), (10, 21)),
 ((7, 4), (11, 28)),
 ((8, 1), (8, 9)),
 ((8, 1), (9, 8)),
 ((8, 2), (10, 16)),
 ((8, 3), (11, 24)),
 ((9, 1), (9, 10)),
 ((9, 1), (10, 9)),
 ((9, 2), (11, 18)),
 ((9, 3), (12, 27)),
 ((10, 1), (10, 11)),
 ((10, 1), (11, 10)),
 ((10, 2), (12, 20)),
 ((11, 1), (11, 12)),
 ((11, 1), (12, 11)),
 ((12, 1), (12, 13))}
95

Widać, że jest 95 różnych par dat spełniających warunki zagadki.

A jak Wam poszło?

1Cichemu wyszło 126. Nie zaliczam.

2Waldek stwierdził za pomocą kilku formuł w Excelu, że 96. Blisko, ale nie zaliczam. Nota bene nie do końca rozumiem Waldkowe formuły - a konkretnie to nie widzę gdzie ma zdefiniowane podwójne permutacje dat (trzeba sprawdzić wszystkie możliwe pary). A może metoda Waldka jest poprawna i się chłop po prostu walnął o 1, na przykład licząc podwójnie parę 2 lutego i 4 kwietnia? No nie wiem.

3Butter jako pierwszy nadesłał poprawne rozwiązanie, uzyskane za pomocą skryptu w Pythonie. Gratuluję wygranej.

from datetime import date, timedelta
res = []
_date = date(2023,1,1)
delta = timedelta(days = 1)

for x in range(365):
    d1 = {
    "day" :_date.day,
    "month" : _date.month,
    "date" :_date}
    res.append(d1)
    
    _date += delta    

wynik = 0
for x in res:
    suma    = x['day'] + x['month']
    iloczyn = x['day'] * x['month']    
    szuk = [ pos for pos in res if ((pos['day'] == suma) and pos['month'] == iloczyn) or ((pos['day'] == iloczyn) and (pos['month'] == suma)) ]
    if len(szuk) >0:
        wynik += len(szuk)
        wynik_print = '{0:02d}-{1:02d} --> '.format(x['day'],x['month'])
        for px in szuk:
            wynik_print += ' {0:02d}-{1:02d} '.format(px['day'],px['month'])
        print(wynik_print)
print('---------')
print(wynik)

Skrypt Buttera (powyżej) jest nieco bardziej skomplikowany od mojego, ale z drugiej strony nie wymaga używania niestandardowych bibliotek i w dodatku wyświetla wyniki w bardziej elegancki sposób:

01-01 -->  02-01  01-02 
02-01 -->  03-02  02-03 
03-01 -->  04-03  03-04 
04-01 -->  05-04  04-05 
05-01 -->  06-05  05-06 
06-01 -->  07-06  06-07 
07-01 -->  08-07  07-08 
08-01 -->  09-08  08-09 
09-01 -->  10-09  09-10 
10-01 -->  11-10  10-11 
11-01 -->  12-11  11-12 
12-01 -->  13-12        
01-02 -->  03-02  02-03
02-02 -->  04-04
03-02 -->  06-05  05-06
04-02 -->  08-06  06-08
05-02 -->  10-07  07-10
06-02 -->  12-08  08-12
07-02 -->  14-09
08-02 -->  16-10
09-02 -->  18-11
10-02 -->  20-12
01-03 -->  04-03  03-04
02-03 -->  06-05  05-06
03-03 -->  09-06  06-09
04-03 -->  12-07  07-12
05-03 -->  15-08
06-03 -->  18-09
07-03 -->  21-10
08-03 -->  24-11
09-03 -->  27-12
01-04 -->  05-04  04-05
02-04 -->  08-06  06-08
03-04 -->  12-07  07-12
04-04 -->  16-08
05-04 -->  20-09
06-04 -->  24-10
07-04 -->  28-11
01-05 -->  06-05  05-06
02-05 -->  10-07  07-10
03-05 -->  15-08
04-05 -->  20-09
05-05 -->  25-10
06-05 -->  30-11
01-06 -->  07-06  06-07
02-06 -->  12-08  08-12
03-06 -->  18-09
04-06 -->  24-10
05-06 -->  30-11
01-07 -->  08-07  07-08 
02-07 -->  14-09
03-07 -->  21-10
04-07 -->  28-11
01-08 -->  09-08  08-09
02-08 -->  16-10
03-08 -->  24-11
01-09 -->  10-09  09-10
02-09 -->  18-11
03-09 -->  27-12
01-10 -->  11-10  10-11
02-10 -->  20-12
01-11 -->  12-11  11-12
01-12 -->  13-12
---------
95

4Rozie nadesłał swoje rozwiązanie nazajutrz rano. Z jakiegoś powodu wyszło mu 48:

days_month_count = {
    1: 31,
    2: 29,
    3: 31,
    4: 30,
    5: 31,
    6: 30,
    7: 31,
    8: 31,
    9: 30,
    10: 31,
    11: 30,
    12: 31,
}

possible = set()
created = set()

for month in range(1, 13):
    for day in range(1, days_month_count[month]):
        possible.add((month, day))
        new_day1 = month * day
        new_month1 = month + day
        new_day2 = month + day
        new_month2 = month * day
        created.add((new_month1, new_day1))
        created.add((new_month2, new_day2))

count = 0
for to_check in created:
    if to_check in possible:
        print(to_check)
        count += 1

print(count)

5Pod wieczór przyszło rozwiązanie Piotra - nie dość, że poprawne, to jeszcze zrobione algorytmem w SQL. Szacun!

with __numbers AS (select * from(values(1),(2),(3),(4),(5),(6)) as n(num)),
_numbers as (select a.* from __numbers a cross join __numbers),
numbers as (select row_number() over(order by a.num) rownum from _numbers a),
longmonthdays as (select rownum day from numbers where rownum <= 31),
shortmonthdays as (select rownum day from numbers where rownum <= 30),
februarydays as (select rownum day from numbers where rownum <= 28),
shortmonths as (select * from (values(4),(6),(9),(11)) as n(month)),
longmonths as (select * from (values (1),(3),(5),(7),(8),(10),(12)) as n(month)),
february as (select 2 as month),
longdates as (select day.*,month.* from longmonthdays day cross join longmonths month),
shortdates as (select day.*, month.* from shortmonthdays day cross join shortmonths month),
februarydates as (select day.*, month.* from februarydays day cross join february month),
alldates as (
                  select day, month from longdates
        union all select day, month from shortdates
        union all select day, month from februarydates
),
datecombinations AS (
    select
        a.day [my day],
        a.month [my month],
        b.day [friend day],
        b.month [friend month]
    from
        alldates a
        inner join alldates b on a.day + a.month = b.month
        and a.day * a.month = b.day
    union
    select
        a.day [my day],
        a.month [my month],
        b.day [friend day],
        b.month [friend month]
    from
        alldates a
        inner join alldates b on a.day * a.month = b.month
        and a.day + a.month = b.day
)
select
    row_number() over(
        order by
            [my day]
    ) num,
    [my day],
    [my month],
    [friend day],
    [friend month]
from
    datecombinations
order by 2, 1

6Rozie zorientował się, że jego poprzednie rozwiązanie miało pewne wady i nadesłał nowe, lepsze. Też mu wyszło 48, ale dużo szybciej i bardziej elegancko:

mm = [1, 2, 3, 4, 6, 12] # possible month after multiplication
ms = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] # possible month after addition

solutions = set()
for m in mm:
    for n in ms:
        if m * n < 31 and m + n < 13:
            solutions.add((m * n, m + n))
        if m + n < 31 and m * n < 13:
            solutions.add((m + n, m * n))
print(len(solutions))

Wydaje mi się, że Rozie próbuje tu rozwiązać inne zadanie niż przedstawione w zagadce...

P.S. Dzięki dla Waldka za przypomnienie mi o terminach - faktycznie kompletnie wyleciało mi z głowy, żeby opublikować odpowiedź. Swoją drogą mam żelazną zasadę nie publikowania zagadki zanim nie przygotuję wpisu z odpowiedzią, więc ten tutaj po prostu wisiał sobie na zapleczu i czekał na publikację. Kwestia paru kliknięć 🙂

7P.S.2. Aha, całkiem zapomniałem o tym, że w międzyczasie - zresztą za namową znajomego - spróbowałem rozwiązać tę zagadkę za pomocą popularnego ostatnio ChatGPT. Oto rezultaty:

Jak widać do osobliwości technologicznej jeszcze daleko 🙂

https://xpil.eu/ywu

9 komentarzy

  1. „licząc podwójnie parę 2 lutego i 4 kwietnia”

    Tak było, tzn tak jest. Rzeczywiście popełniłem niegodny błąd i czuję się wstrętnie.
    Przyznam, że szukałem haczyków w tej zagadce i sprawdzałem na różne sposoby wiele z nich (np. datę 29 lutego). Przeoczyłem jednak oczywiste. Tak mi wstyd…
    Naprawdę.

  2. „Swoją drogą mam żelazną zasadę nie publikowania zagadki zanim nie przygotuję wpisu z odpowiedzią, więc ten tutaj po prostu wisiał sobie na zapleczu i czekał na publikację”.

    Znaczy – znałeś nasze odpowiedzi, zanim my je uzyskaliśmy:

    Bądź uwielbiony, miłosierny Boże, Wszechmocny Stwórco, dobry nasz Panie.
    Cześć Ci oddajem w najgłębszej pokorze, w Bóstwa Twojego tonąc oceanie.

    1. Jakiś hymn czy dwa, spoko, ale aż takie rymy to mi się jednak nie należą.

      Chodziło mi bardziej o to, że zanim opublikuję zagadkę, mam już przygotowany wpis z odpowiedzią. Natomiast ponumerowane po kolei zgłoszenia czytelników dopisuję na bieżąco później.

      Zresztą w tym akurat przypadku między nadejściem odpowiedzi numer 6 a publikacją wpisu minęło całkiem sporo czasu, więc wszystko się zgadza.

      1. Te peany to tylko drobny żarto-uśmiech ściągnięty z jakiejś przypadkowej strony religio-wyznawców. Tak poza tym to, rzecz jasna, nie możesz być Bogiem, gdyż zapomniałeś o dacie publikacji rozwiązania. Bóg by nie zapomniał…

        1. W jednej z książek Pratchetta była bogini odpowiedzialna za blokowanie się chochli w szufladzie. Ja mogę być bogiem od zapominania. Panteon teraz jest pełen najróżniejszego dziwactwa 🙂

  3. Więc bądź uszafladowiona, bogini chochli.

    Jeśli już o bogach i bóstwach: Bardzo, ale to najbardziej bardzo spodobał mi się cytat:
    „If you broke down holy water into hydrogen and oxygen you could make a holy hydrogen bomb”.
    Kilka cytatów z twojej strony już wcześniej mi się podobało (z siedem razy nawet się śmiałem), ale ten przebija wszystko. To jest KWINTESENCJA. Trzeba tylko spojrzeć w głąb. W głąb bomby wodorowej. Serdecznie pozdrawiam…

  4. Ech, machnąłem się w warunku poprawności miesiąca i w niektórych przypadkach zaliczyło mi daty z miesiącami większymi od 12 – nie wiem, jakim cudem udało mi się tego nie zauważyć w wynikach. Po poprawieniu wyszło już dobrze.

  5. Nie tylko liczyłem co innego, niż przedstawione w zagadce, ale dodatkowo z błędem. Chodzi oczywiście o linię

    for day in range(1, days_month_count[month]):
    

    Za mało o 1 w górnym zakresie.

    I tak, policzyłem po prostu ile unikalnych dat można utworzyć przez mnożeniododawanie.

Leave a Comment

Komentarze mile widziane.

Jeżeli chcesz do komentarza wstawić kod, użyj składni:
[code]
tutaj wstaw swój kod
[/code]

Jeżeli zrobisz literówkę lub zmienisz zdanie, możesz edytować komentarz po jego zatwierdzeniu.