Vấn đề mười hai đồng xu


14

Lý lịch

Vấn đề mười hai đồng xu là một câu đố cân bằng cổ điển thường được sử dụng trong các cuộc phỏng vấn việc làm. Câu đố xuất hiện lần đầu tiên vào năm 1945 và được ông tôi đặt cho bố tôi khi ông yêu cầu cưới mẹ tôi! Trong câu đố có mười hai đồng xu, một trong số đó nặng hơn hoặc nhẹ hơn những đồng xu khác (bạn không biết cái nào). Vấn đề là sử dụng thang cân bằng ba lần để xác định đồng tiền duy nhất. Trong một số biến thể, cũng cần xác định xem đồng xu nặng hơn hay nhẹ hơn.

Nhiệm vụ ở đây liên quan đến việc giải quyết vấn đề chung liên quan đến n xu, sử dụng trọng lượng ít nhất có thể trong trường hợp xấu nhất. Không cần thiết phải xác định xem đồng xu nặng hơn hay nhẹ hơn, chỉ có nó là đồng xu nào. Hơn nữa, bạn không có quyền truy cập vào bất kỳ đồng tiền bổ sung nào ngoài bộ đã cho (điều này, thật tò mò, tạo ra sự khác biệt).

Hóa ra trọng lượng k là đủ cho tối đa (3 ^ k-1) / 2 đồng xu (vì vậy 4 lần cân trong biến thể này thực sự có thể xử lý 13 đồng xu). Hơn nữa (và đáng ngạc nhiên), có thể (nhưng không bắt buộc ở đây) để chọn toàn bộ cân trước, thay vì cân trong tương lai phụ thuộc vào kết quả trong quá khứ. Để biết mô tả về hai giải pháp có thể, hãy xem bài viết nàycâu trả lời Quora này .

Bài tập

Viết hàm hoặc chương trình, lấy số nguyên n làm đầu vào thông qua STDIN, đối số dòng lệnh hoặc đối số hàm, để giải quyết vấn đề cho n xu bằng cách sử dụng số lượng ít nhất có thể trong trường hợp xấu nhất. Chương trình nên:

  • In trọng lượng sang STDOUT theo định dạng 1,2,3-4,5,6để chỉ ra danh sách các đồng tiền ở mỗi bên của thang đo. Bất kỳ đồng tiền không được cân không nên được đề cập. Các đồng tiền được đánh số ngầm định từ 1 đến n và không cần phải in theo thứ tự số ( 2,1-3,4tương tự như vậy 1,2-3,4).
  • Sau mỗi chương trình nặng nên chờ đợi vào một đầu vào thông qua STDIN, mà nên <, =hay >, cho thấy dù ở phía bên trái của quy mô là nhẹ hơn, giống nhau, hoặc nặng hơn bên phải.
  • Sau kết quả cân cuối cùng, chương trình sẽ in hoặc trả về số lượng đồng xu duy nhất.
  • Chương trình không cần xử lý đầu vào kết quả không nhất quán từ người dùng.
  • Chương trình không cần xử lý n dưới 3.

Ví dụ đầu ra

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

Chấm điểm

Mã ngắn nhất sẽ thắng. Quy tắc chuẩn áp dụng.

Câu trả lời:


2

Python 3: 497 byte

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)))))

Tôi nghi ngờ điều này có thể được thu nhỏ lại một chút, nhưng tôi không thấy bất kỳ địa điểm rõ ràng nào nữa (sau khoảng 5 phiên bản khác nhau của mỗi chức năng).

Mã thực hiện một phiên bản sửa đổi một chút của thuật toán từ trang này bằng ba hàm. Các Ichức năng thực hiện các IO (in các tùy chọn và trở về phản ứng của người dùng). Các hàm ABhàm thực hiện chính của thuật toán.Alấy hai danh sách có kích thước khác nhau theo chính xác một yếu tố (mặc dù một trong hai danh sách có thể là danh sách lớn hơn): một đồng xu trong acó thể nhẹ hơn bình thường hoặc một đồng xu trong bcó thể nặng hơn. Blàm nhiệm vụ kép. Nó lấy một danh sách các đồng tiền avà tùy chọn một danh sách thứ hai với một đồng xu duy nhất được biết là đúng trọng lượng. Hành vi làm tròn độ dài cần phải khác nhau giữa hai trường hợp, điều này gây ra không có kết thúc đau đầu.

Hai hàm thuật toán có thể tìm thấy đồng xu có trọng số bất thường trong các lần kcân cho các đầu vào có kích thước sau:

  • A: 3^ktổng số tiền, được chia thành hai danh sách(3^k-1)/2(3^k+1)/2.
  • B: (3^k + 1)/2tiền nếu một đồng tiền tốt được cung cấp,(3^k - 1)/2 nếu không.

Câu hỏi được đặt ra ở đây chỉ ra rằng chúng ta không có bất kỳ đồng tiền nào được biết đến khi bắt đầu, vì vậy chúng ta có thể giải quyết việc tìm ra đồng tiền xấu trong một tập hợp (3^k - 1)/2 trong kweighings.

Đây là một chức năng kiểm tra mà tôi đã viết để đảm bảo mã của tôi không yêu cầu cân nặng không có thật hoặc sử dụng nhiều hơn số lượng cân được cho là:

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

Điều này in ra số lượng cân nặng trong trường hợp xấu nhất cho một bộ nhất định sau khi thử nghiệm với mỗi sự kết hợp của đồng xu và trọng lượng xấu (nặng hoặc nhẹ).

Đây là đầu ra thử nghiệm cho các bộ lên tớ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

Các điểm dừng chính xác là nơi bạn mong đợi, giữa (3^k - 1)/2(3^k + 1)/2.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.