101枚硬币中有一枚假币, 有一个无砝码的天平, 在最坏情况下最少称多少次,可以判断假币比真币重还是轻

首先看一道商汤的笔试题:

  1. [商汤]101枚硬币中有一枚假币,有一个无砝码的天平,在最坏情况下最少称 多少 次,可以判断假币比真币重还是轻。

解法1: 两次

//Heavier: true, lighter: false
FakeCoin1:
  divide coins S into (A: 50, B: 50, C: 1)
  if A == B:
    return C > A[0] 
  else:
    return min(A,B)[:25] == min(A,B)[25:]

解法2: 两次

//Heavier: true, lighter: false
FakeCoin2:
  divide coins S into (A: 33, B: 33, C: 35)
  if A == B:
    return C > (A+B)[:|C|] 
  else:
    return min(A,B) == C[:|B|]

解法3: 两次

//Heavier: true, lighter: false
FakeCoin3:
  divide coins S into (A: 33, B: 33, C: 35)
  if A == B:
    return C > (A+B)[:|C|] 
  elif A > B:
    return C >= min(A,B)+max(A,B)[:|C|-|A|]

三种解法的共同约束为\(C=S-A-B, |A|=|B|\)

解法1. 要求\(|A|\%2=0, |A|=\lfloor\frac{|S|}2\rfloor\), 显然只能处理数量为4k+1的硬币堆.

	a). 如果A==B, 显然C假币. 此时A,B构成类(划分)间、类内等价, 从A,B中任取一个硬币与C比较即可		
	b). 如果A!=B, 显然C真币. 此时A异或B构成类内等价, 对半划分A或B确定其类内等价性即可

解法2. 要求\(|A|\leq|C|\leq 2|A|\)\(3|A| \leq |S| \leq 4|A|\).

	a). 如果A==B, C类内等价无假币. (A+B)的子集若较C重则假币较重, 否则较轻
	b). 如果A!=B, 使用C的子集与min(A,B)比较, 若相等则假币较重, 否则较轻

解法3. 要求\(|A| \leq |C| \leq 2|A|\)\(3|A| \leq |S| \leq 4|A|\).

	a). 如果A==B, C类内等价无假币. (A+B)的子集若较C重则假币较重, 否则较轻
	b). 如果A!=B, 使用C的子集与min(A,B)+max(A,B)[:|C|-|A|]比较
			min(A,B)包含较轻假币 -> min(A,B)+max(A,B)[:|C|-|A|] < C;
			max(A,B)包含较重假币 -> min(A,B)+max(A,B)[:|C|-|A|] >= C;
			假币的轻重和比较判定式均是划分(不交不漏)且是双射(互为充要条件)

总结三种解法适用于不同的划分要求, 其中解法1的划分可以直接构造一个类内等价的单元素类但限制是硬币总数为4k+1, \(a_n=2*a_{n-1}+1, a1=3\)序列下的任意一个数可以使得解法一退化成\(O(logN)\)复杂度.对于算法2.3, 其划分要求一致但后判使用了两种不同的策略, 解法3相比解法2更晦涩难懂.

posted @ 2020-03-27 17:26  xiconxi  阅读(723)  评论(0编辑  收藏  举报