n枚硬幣問題(找假幣)


問題描述:

在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
  1. 首先獲取真幣,通過從數組中隨機取三枚硬幣,互相比較,相等的兩枚為真幣,任意取一枚作為真幣 記錄 數組下標
  2. 判斷n中的硬幣數量,如果n>2則執行3,否則執行5.
  3. 將n分為上圖的四堆,拿 a 和 b 比較,如果 a == b ,則 假幣在 c 或 d 中。否則假幣在 a 或 b 中。
  4. 如果 a == b,則拿 a 和 c 比較。如果 a == c,則假幣在d中。將 d 再次 執行本流程。如果不等,則假幣在 c 中,將 d (余數堆) 再次 執行流程,並且n=n%3,。
  5. 如果 a != b,則拿 a 和 c 比較。如果 a == c,則假幣在b中。將 b 再次 執行本流程。如果不等,則假幣在 a 中,將 a 再次 執行流程  2,並且n=(n-n%3)/3。
  6. 如果n==2,則將兩枚硬幣與真的硬幣(通過 數組下標 )進行比較,不同的為假幣,輸出結果,結束。
  7. 如果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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM