1. 程式人生 > >一道經典面試邏輯題的python解法

一道經典面試邏輯題的python解法

前言:

好早之前看到的一個邏輯題:有兩個2到99之間的整數,a知道這兩個數的和,b知道這兩個數的積。

第一句:a對b說:我不知道這兩個數是多少,但我確信你也不知道。

第二句:b說:我知道了。

第三句:a說:我也知道了。

問這兩個數是多少? 題不難,只是手動去找沒有python寫程式找的快,而且用python程式可以在後面進行進一步的探索。

分析:

首先是a手上的數是兩個數的和,那是在[4,198]之間。

第一句話分析:a確信b不知道這兩個數

(1)

比如a手上的數字是8,那麼要求的兩個數字就有可能是(2,6),(3,5),(4,4)這三種情況,對應的b手上的數字就可能是12,15,16這三種情況,這是來自a的視角。

但簡單分析,第一句話 a確信b不知道這兩個數字是多少。那麼b手上的數字肯定不可能是15,為什麼呢?因為15只有一種分解情況(兩個素數相乘):3*5。如果b手上是15,那麼b肯定知道這兩個數字是3和5了。

進而可以分析出 a 手上的數字肯定不是8, 因為a手上是8的話,那b手上可能的三種情況(12,15,16) 其中的15這種情況,b是可以分析出這兩個數字分別是多少的,而a確信b不知道,所以可以排除8。

進一步,那a手上什麼數字可以排除掉呢?通過上面的分析,

可以得出 結論(1):a是不能分解成兩個素數的和,凡是可以分解成兩個素數的和的情況,b是可以知道這兩個數的

上python程式碼:


asum1裡面存了a手上還可能的數,54個(排除了那些能分解成兩個素數的數)

(2)

上面的54個可能裡面全是奇數,沒有偶數。

進一步分析:a 手上的數字也不能寫成(53+2*x,x>=2)這種形式,因為如果可以分解成這種形式,b=53*2*x,因為兩個數是小於等於99的,53*2>99了,也只有一種分解情況53,2*x,進而b也知道這兩個數字了。

所以結論(2):比上限/2(99/2=49.5)大的第一個素數(53),+3(56)以後的數字就排除了。

為什麼是+3,因為2*x最小是4.

所以經過第一句話後,a手上的數字asum2集合 還剩11個

[11, 17, 23, 27, 29, 35, 37, 41, 47, 51, 53]   <-asum2

把他們分解了,相乘得到b的粗略集合:


第二句話分析:b知道了

b在什麼情況下可以說這樣的話呢? 

比如b =24, 那麼可能的分解(2,12),(3,8),(4,6)兩種情況,那麼對於的 a就是14,11和10三種情況,這是來自b的視角。

剛開分析了那麼多得出a手上剩下的可能性:[11, 17, 23, 27, 29, 35, 37, 41, 47, 51, 53],這個集合的意思是當a手上是這些數的時候a才敢說第一句話,反言之a手上不是這些數時a就不敢說這些話。

那麼24分解出來得到的 14,11和10三種情況:14,10不在a可能集合裡,11在可能集合裡。

11是唯一一個在a可能集合裡的,所以b可以分析出a手上的數字是11,因為如果是其他兩個數的話,a不敢說第一句話。

進而得出一個結論:b分解出來的所有兩個數eg:(2,12),(3,8),(4,6)所組成的和eg:14,11和10, 有且只有一個存在在a的可能集合裡


經過第二句話b手上可能數字有102個,存入bmul1

第三句話分析:a知道了

和第二句話一模一樣的分析,a為什麼能知道?唯一的可能性就是a手上的數的分解後組成的積有且只有一種情況在集合bmul1裡(第二句話算出的集合b)


現在就只有唯一一個結果了。

輸出結果


原題到這裡就結束了,後面可以展開一些思考。

(1)既然得出的結論是4和13,不算大,而條件給的是2-99,那麼有沒有可能把條件範圍給小一點,比如給2-20來降低題目難度呢,畢竟這樣計算量要小很多。程式裡面可以直接把初始條件從99改成20,結果是沒有找到符合要求的兩個數。為什麼呢?

原因是雖然4和13小於20,但a看到的是17,那麼有可能分解成8和9,在a的視角b的數字有可能是72,同時在b的視角的可以分解成2*36,這個36就一下大於20了哦。 

那麼把題目換個有趣的問法,同樣的對話,兩個數字的範圍是2-N,N至少取多大,才能保證至少有一個解? 

用程式解很簡單,讓N從10到99進行一次遍歷,看從哪次開始有解了就輸出

得到的結論是:N至少是64才有一個解,(4,13)

(2) 那麼把N擴大,範圍擴大,解會變多嗎

如果範圍擴大到2-999了,有了第二個解4,61。大家可以思考一下為什麼範圍在2-99的時候沒有出現這個解

範圍擴大到2-9999了,算出來了13個解,分別是: 

1 兩個數和: 17 兩個數積: 52

兩個數為: [4, 13]

2 兩個數和: 65 兩個數積: 244

兩個數為: [4, 61]

3 兩個數和: 89 兩個數積: 1168

兩個數為: [16, 73]

4 兩個數和: 127 兩個數積: 1776

兩個數為: [16, 111]

5 兩個數和: 137 兩個數積: 4672

兩個數為: [64, 73]

6 兩個數和: 163 兩個數積: 4192

兩個數為: [32, 131]

7 兩個數和: 179 兩個數積: 2608

兩個數為: [16, 163]

8 兩個數和: 185 兩個數積: 724

兩個數為: [4, 181]

9 兩個數和: 191 兩個數積: 8128

兩個數為: [64, 127]

10 兩個數和: 233 兩個數積: 916

兩個數為: [4, 229]

11 兩個數和: 247 兩個數積: 1912

兩個數為: [8, 239]

12 兩個數和: 343 兩個數積: 9952

兩個數為: [32, 311]

13 兩個數和: 373 兩個數積: 19776

兩個數為: [64, 309]