defSumOfGenerator(n): maxValue = n >> 1 minValue = max(Min, n - Max) if n & 1: # 两个数不会相同 maxValue += 1 for i in range(minValue, maxValue): yield (i, n - i) defMulOfGenerator(n): _maxValue = math.sqrt(n) _minValue = n / Max minValue, maxValue = int(_minValue), int(_maxValue) if maxValue != _maxValue: # 两个数不会相同 maxValue += 1 if minValue != _minValue: minValue += 1 minValue = max(Min, minValue) for i in range(minValue, maxValue): if n % i == 0: # 由于Max不大,这里没必要用质因数来做 yield(i, n // i)
# 1. 庞涓对孙膑说:虽然我无法确定这两个数是什么,但我肯定你也不知道这两个数是什么。 defStep1(s):#庞涓视角,拿到两个数的和s for (a, b) in SumOfGenerator(s): #对于任何可能的组合 m = a * b if len(list(MulOfGenerator(m))) == 1: #若某个组合只有一种分解情况 returnFalse#那你就知道这两个数是什么了,所以这是不可能的 return s > Min * 2 + 1#且我不知道这两个数是什么
# 2. 孙说:我本来不知道,但是你这么说,我就知道了。 defStep2(m):#孙膑视角,他知道两个数的积m solveNum = 0 for (a, b) in MulOfGenerator(m): #对于任何可能的组合 if Step1(a + b): #经过前一个条件的筛选 solveNum += 1 if solveNum >= 2: #如果还有至少两个解,那我没法确定这两个数,矛盾 returnFalse return solveNum == 1# 当然,没解也是不行的 # 3. 庞说:既然你知道了,那我也就知道了。 defStep3(s):#庞涓视角,他知道两个数的和s solveNum = 0 for (a, b) in SumOfGenerator(s): #对于任何可能的组合 if Step1(a + b) and Step2(a * b): solveNum += 1 if solveNum >= 2: #如果还有至少两个解,那我没法确定这两个数,矛盾 returnFalse return solveNum == 1# 当然,没解也是不行的
哈,原来挺简单的嘛。接下来,只要全面筛选就行啦!
1 2 3 4
for a in range(Min, Max): for b in range(a + 1, Max + 1): if Step1(a + b) and Step2(a * b) and Step3(a + b): print("a = %d, b = %d" % (a, b))
果然,我们得到了唯一解:a = 4, b = 13。将Max往前回溯一下发现,Max最小为62时有解;往前拓展发现一直都是这一个解,但当Max比较大(比如你可以试试700)的时候需要跑上几分钟了。
Step3Table = [None] * (Max * 2 + 1) defStep3(n): if Step3Table[n] isNone: solveNum = 0 flag = True for (a, b) in SumOfGenerator(s): #对于任何可能的组合 if Step1(a + b) and Step2(a * b): solveNum += 1 if solveNum >= 2: #如果还有至少两个解,那我没法确定这两个数,矛盾 flag = False break Step3Table[n] = flag and solveNum == 1# 当然,没解也是不行的
return Step3Table[n]
那对于Step2呢?我们的列表长度可能要扩展到Max * Max + 1,这实在是太占用空间了,而中间其实有很多用不到的下标。为此,我们采用字典方式存储。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
Step2Table = {} defStep2(n): ifnot n in Step2Table.keys(): solveNum = 0 flag = True for (a, b) in MulOfGenerator(m): #对于任何可能的组合 if Step1(a + b): #经过前一个条件的筛选 solveNum += 1 if solveNum >= 2: #如果还有至少两个解,那我没法确定这两个数,矛盾 flag = False break Step2Table[n] = flag and solveNum == 1# 当然,没解也是不行的
def__getitem__(self, key): index = key if self.StoreInList: index -= self.IndexOffset assert(0 <= index < self.IndexRange) if self.Cache[index] isNone: self.Cache[index] = self.DefaultFunction(key) elifnot key in self.Cache.keys(): self.Cache[index] = self.DefaultFunction(key) return self.Cache[index]
defSolveGenerator(self): for a in range(self.Min, self.Max + 1): for b in range(a + 1, self.Max + 1): if self.Step1Cache[a + b] and self.Step2Cache[a * b] and self.Step3Cache[a + b]: yield (a, b)
defSumOfGenerator(self, n): maxValue = n >> 1 minValue = max(self.Min, n - self.Max) if n & 1: maxValue += 1 for i in range(minValue, maxValue): yield (i, n - i)
defMulOf(self, n): mulOf = [] _maxValue = math.sqrt(n) _minValue = n / self.Max minValue, maxValue = int(_minValue), int(_maxValue) if maxValue != _maxValue: maxValue += 1 if minValue != _minValue: minValue += 1 minValue = max(self.Min, minValue) for i in range(minValue, maxValue): if n % i == 0: mulOf.append(i) return mulOf
defStep1(self, s): for (a, b) in self.SumOfGenerator(s): m = a * b if len(self.MulOfCache[m]) == 1: returnFalse return s > self.Min * 2 + 1
defStep2(self, m): solveNum = 0 for a in self.MulOfCache[m]: b = m // a if self.Step1Cache[a + b]: solveNum += 1 if solveNum >= 2: returnFalse return solveNum == 1 defStep3(self, s): solveNum = 0 for (a, b) in self.SumOfGenerator(s): if self.Step1Cache[a + b] and self.Step2Cache[a * b]: solveNum += 1 if solveNum >= 2: returnFalse return solveNum == 1