この記事は Google 翻訳を使用して処理されました
問題の説明
コインは $n$ 枚あり、そのうち 1 枚は偽造コインであり、偽造コインの方が軽いことが分かっています。今では残高は 1 つだけなので、できるだけ少ない比較で偽造コインを見つける必要があります。
問題分析
$n$ 枚のコインを 2 つの等しい部分に分割します。
- $n$ が偶数の場合、最初の部分と2番目の部分、$1\cdots\frac{n}{2}$ と $\frac{n}{2}+1\cdots n$ を2つのスケールの端と端を照らします。軽い方の端に偽造コインが含まれています。同じ方法を使用して、コインの軽い部分にある偽造コインを見つけます。
- $n$ が奇数の場合、最初と最後の部分 $1\cdots\frac{n-1}{2}$ と $\frac{n+1}{2}+1\cdots n$ を、天秤の軽い方の端に偽造コインがあります。同じ方法を使用して、コインの軽い部分にある偽造コインを見つけ続けます。両端の重さが同じであれば、真ん中のコインは偽造コインです。つまり、$\frac{n+1}{2}$ 枚のコインは偽造品である。
Cコード
#include <stdio.h>
// coins:重量配列 first,last:配列の最初と最後の添え字
int getCounterfeitCoin(int *coins, int first, int last);
int main(void){
int coins[10] = {2,2,1,2,2,2,2,2,2,2};
int tmp = getCounterfeitCoin(coins, 0, 9);
printf("%d は偽造コインです\n",tmp+1);
return 0;
}
int getCounterfeitCoin(int *coins, int first, int last){
int firstSum=0; int lastSum=0;
int i;
// 残りコインは2枚のみ
if(first == last -1){
if(coins[first] < coins[last])
return first;
return last;
}
// 偶数枚のコイン
if ((last-first+1)%2 == 0){
for(i=first; i<first+(last-first)/2+1; i++){
firstSum += coins[i];
}
for(i=first+(last-first)/2+1; i<last+1; i++){
lastSum += coins[i];
}
if(firstSum < lastSum){
return getCounterfeitCoin(coins, first, first+(last-first)/2);
}else{
return getCounterfeitCoin(coins, first+(last-first)/2+1, last);
}
}else{ // 奇数のコイン
for(i=first; i<first+(last-first)/2; i++){
firstSum += coins[i];
}
for(i=first+(last-first)/2+1; i<last+1; i++){
lastSum += coins[i];
}
if(firstSum < lastSum){
return getCounterfeitCoin(coins, first, first+(last-first)/2-1);
}else if(firstSum > lastSum){
return getCounterfeitCoin(coins, first+(last-first)/2+1, last);
}else{
return first+(last-first)/2;
}
}
}