Проблема дванадцяти монет


14

Фон

Проблема дванадцяти монет - це класична головоломка, яка зазвичай використовується на співбесідах. Вперше головоломка з’явилася в 1945 році і була поставлена ​​моїм дідом мого діда, коли він попросив одружитися з моєю матір’ю! У головоломці дванадцять монет, одна з яких або важча, або легша за інші (ви не знаєте, яка). Проблема полягає у використанні балансової шкали тричі для визначення унікальної монети. У деяких варіаціях також слід визначити, чи монета важча, чи легша.

Завдання тут полягає у вирішенні загальної проблеми із залученням російських монет, використовуючи найменше зважування, можливе в гіршому випадку. Не слід визначати, чи монета важча, чи легша, лише яка вона. Крім того, у вас немає доступу до будь-яких додаткових монет за межами заданого набору (що, що цікаво, має значення).

Виявляється, k зважування достатньо для монет до (3 ^ k-1) / 2 (тому 4 зважування в цьому варіанті насправді можуть обробляти 13 монет). Крім того, (і що дивно), можна (але не вимагати тут) повний набір зважувань заздалегідь, а не майбутні зважування залежать від минулих результатів. Описи двох можливих рішень див. У цій роботі та відповіді Quora .

Завдання

Напишіть функцію або програму, взявши ціле число n як вхід через STDIN, аргумент командного рядка або аргумент функції, який вирішує проблему для n монет, використовуючи найменші зважування, можливі в гіршому випадку. Програма повинна:

  • Роздрукуйте зважування до STDOUT у форматі, 1,2,3-4,5,6щоб вказати списки монет на кожній стороні шкали. Будь-які монети, які не зважуються, не слід згадувати. Монети неявно пронумеровані від 1 до n і не повинні друкуватися в цифровому порядку (так 2,1-3,4само, як і в 1,2-3,4).
  • Після кожного зважування програма повинна чекати на вхід через STDIN, який повинен бути <, =або із >зазначенням того, що ліва частина шкали світліша, однакова чи важча за праву.
  • Після останнього результату зважування програма повинна надрукувати або повернути номер унікальної монети.
  • Програмі не потрібно обробляти непослідовні введення результатів від користувача.
  • Програмі не потрібно обробляти n менше 3.

Приклади виходів

>> 3
1-2
>> =
1-3
>> <
3

# using Quora algorithm
>> 13
1,2,3,4-5,6,7,8
>> <
1,2,5-3,4,6
>> >
3-4
>> <
3

# using paper algorithm
>> 13
1,2,3,4-5,6,7,8
>> <
2,6,7,9-3,8,10,11
>> >
6,8,10,12-4,5,7,11
>> =
3

Оцінка балів

Найкоротший код виграє. Діють стандартні правила.

Відповіді:


2

Пітон 3: 497 байт

I=lambda a,b:input(",".join(a)+"-"+",".join(b)+"\n>> ")
def A(a,b):
 l,L=len(a),len(b)
 if l+L==1:return(a or b)[0]
 m=(2*l+1-L)//3;M=m+L-l;x,y,X,Y=a[:m],a[m:2*m],b[:M],b[M:2*M];r=I(x+X,y+Y);return A(a[2*m:],b[2*M:])if r=="="else A(x,Y)if r=="<"else A(y,X)
def B(a,n=[]):
 if len(a)==1:return a[0]
 m=len(n);l=(len(a)+1+m)//3;x,y,z=a[:l],a[l:2*l-m],a[2*l-m:];r=I(x,y+n);return B(z,a[:1])if r=="="else A(x+z[:1-m],y)if r=="<"else A(y+z[:1-m],x)
print(B(list(map(str,range(1,int(input("N= "))+1)))))

Я підозрюю, що це може бути зменшено трохи більше, але я більше не бачу очевидних місць (приблизно через 5 різних версій кожної функції).

Код реалізує трохи змінену версію алгоритму з цієї сторінки, використовуючи три функції. IФункція робить IO (друк параметрів і повертається відповідь користувача). Функції Aта Bфункції реалізують головне алгоритму. Aбере два списки, які різняться за розміром точно на один елемент (хоча будь-який список може бути більшим): одна монета aможе бути легшою, ніж звичайна, або одна монета bможе бути важчішою.Bвиконує подвійне мито. Він займає один список монет aі необов'язково другий список з однією монетою, яка, як відомо, має правильну вагу. Поведінка округлення довжин має бути різною між двома випадками, що не спричинило закінчення головного болю.

Дві функції алгоритму можуть знайти незвичайно зважену монету при kзважуванні із заданими входами до таких розмірів:

  • A: 3^kзагальні монети, розділені на два списки (3^k-1)/2та (3^k+1)/2.
  • B: (3^k + 1)/2монети, якщо монета з добре відомим (3^k - 1)/2 способом поставляється, інакше.

Питання , поставлене тут вказує , що у нас немає жодних - або свідомо хороші монети на початку, так що ми можемо вирішити знайти погану монету в наборі (3^k - 1)/2в kзважувань.

Ось тестова функція, яку я написав, щоб переконатися, що мій код не запитував фіктивне зважування або використовував більше кількості зважувань, які він повинен був:

def test(n):
    global I
    orig_I = I
    try:
        for x in range(3,n+1):
            max_count = 0
            for y in range(x*2):
                count = 0
                def I(a, b):
                    assert len(a) == len(b), "{} not the same length as {}".format(a,b)
                    nonlocal count
                    count += 1
                    if y//2 in a: return "<"if y%2 else ">"
                    if y//2 in b: return ">"if y%2 else "<"
                    return "="
                assert B(list(range(x)))==y//2, "{} {} not found in size {}".format(['heavy','light'][y%2], y//2+1, x)
                if count > max_count:
                    max_count = count
            print(x, max_count)
    finally:
        I = orig_I

Це виводить найгірше число зважувань для даного набору після тестування з кожною комбінацією монети та поганою вагою (важкою або легкою).

Ось тестовий вихід для наборів до 125:

>>> test(150)
3 2
4 2
5 3
6 3
7 3
8 3
9 3
10 3
11 3
12 3
13 3
14 4
15 4
16 4
17 4
18 4
19 4
20 4
21 4
22 4
23 4
24 4
25 4
26 4
27 4
28 4
29 4
30 4
31 4
32 4
33 4
34 4
35 4
36 4
37 4
38 4
39 4
40 4
41 5
42 5
43 5
44 5
45 5
46 5
47 5
48 5
49 5
50 5
51 5
52 5
53 5
54 5
55 5
56 5
57 5
58 5
59 5
60 5
61 5
62 5
63 5
64 5
65 5
66 5
67 5
68 5
69 5
70 5
71 5
72 5
73 5
74 5
75 5
76 5
77 5
78 5
79 5
80 5
81 5
82 5
83 5
84 5
85 5
86 5
87 5
88 5
89 5
90 5
91 5
92 5
93 5
94 5
95 5
96 5
97 5
98 5
99 5
100 5
101 5
102 5
103 5
104 5
105 5
106 5
107 5
108 5
109 5
110 5
111 5
112 5
113 5
114 5
115 5
116 5
117 5
118 5
119 5
120 5
121 5
122 6
123 6
124 6
125 6

Точки переривання - саме там, де ви очікували, між (3^k - 1)/2та (3^k + 1)/2.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.