問題描述:
在n枚外觀相同的硬幣中,有一枚是假幣,並且已知假幣與真幣的重量不同,但不知道假幣與真幣相比較輕還是較重。可以通過一架天平來任意比較兩組硬幣,設計一個高效的算法來檢測這枚假幣。
解題思路:
使用減治法的解題思路,將硬幣分為3堆,則每堆的硬幣數量為 n/3 ,但是這是在 n%3==0 的情況下才能成立,所以我們將 n 枚硬幣分為 3 堆加 1 堆 余數堆(余數堆可能為0),則可分為如下(n-n%3)/3, (n-n%3)/3, (n-n%3)/3, n%3.
如下圖:
(n-n%3)/3
(n-n%3)/3
(n-n%3)/3
n%3
a
b
c
d
- 首先獲取真幣,通過從數組中隨機取三枚硬幣,互相比較,相等的兩枚為真幣,任意取一枚作為真幣 記錄 數組下標。
- 判斷n中的硬幣數量,如果n>2則執行3,否則執行5.
- 將n分為上圖的四堆,拿 a 和 b 比較,如果 a == b ,則 假幣在 c 或 d 中。否則假幣在 a 或 b 中。
- 如果 a == b,則拿 a 和 c 比較。如果 a == c,則假幣在d中。將 d 再次 執行本流程。如果不等,則假幣在 c 中,將 d (余數堆) 再次 執行流程,並且n=n%3,。
- 如果 a != b,則拿 a 和 c 比較。如果 a == c,則假幣在b中。將 b 再次 執行本流程。如果不等,則假幣在 a 中,將 a 再次 執行流程 2,並且n=(n-n%3)/3。
- 如果n==2,則將兩枚硬幣與真的硬幣(通過 數組下標 )進行比較,不同的為假幣,輸出結果,結束。
- 如果n==1,則該硬幣就是假幣,輸出結果結束。
*注:按照2-5流程分堆下去,在最后一執行流程 2 時,n中含有假幣,並且n只可能為1或2.(初始時,n>3,若n<3,則不能判斷真假)
主要代碼如下:
1 //計算硬幣總重量 2 int sum_coin(int coin[],int m,int n){ 3 int result=0; 4 if(m>n) 5 return 0; 6 for(int i=m;i<=n;i++){ 7 result+=coin[i]; 8 } 9 10 return result; 11 }; 12 13 14 //找出假幣 m , n 數組下標,coin 硬幣數組,relCoin 真幣數組下標 15 int check_coin(int coin[],int m,int n,int& relCoin){ 16 17 int vary=n-m+1; 18 19 int restCoin=vary%3; 20 int vary2=vary-restCoin; 21 22 if(vary==1) 23 return m; 24 25 if(vary==2) 26 { 27 if(sum_coin(coin,m,m)==sum_coin(coin,relCoin,relCoin)) 28 return n; 29 else 30 return m; 31 32 } 33 34 35 if(sum_coin(coin,m,m+vary2/3-1)==sum_coin(coin,m+vary2/3,m+(vary2/3)*2-1))//第一堆 == 第二堆 36 { 37 if( (sum_coin(coin,m,m+vary2/3-1)==sum_coin(coin,m+(vary2/3)*2,m+vary2-1)))//第一堆 == 第三堆 38 check_coin(coin,n-restCoin+1,n,relCoin); 39 else//第一堆 != 第三堆 40 check_coin(coin,m+(vary2/3)*2,m+vary2-1,relCoin); 41 } 42 else//第一堆 != 第二堆 43 { 44 if(sum_coin(coin,m,m+vary2/3-1)==sum_coin(coin,m+(vary2/3)*2,m+vary2-1))//第一堆 == 第三堆 45 check_coin(coin,m+vary2/3,m+(vary2/3)*2-1,relCoin); 46 else//第一堆 != 第三堆 47 check_coin(coin,m,m+vary2/3-1,relCoin); 48 } 49 50 }; 51 52 53 //返回真幣數組下標 54 int getRelCoin(int coin[],int m,int n) 55 { 56 if(n-m+1<=2) 57 { 58 cout<<"硬幣數小於3枚!!!無解"; 59 return -1; 60 } 61 else 62 { 63 if(coin[0]==coin[1]) 64 { 65 return 0; 66 } 67 else 68 { 69 if(coin[0]==coin[2]) 70 return 2; 71 else 72 { 73 return 1; 74 } 75 } 76 } 77 78 };
原創,轉載請注明來源,
默@語:www.h-five.com