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