在n枚外观相同的硬币中,有一枚硬币是假币,但是不知道假币的重量是较重还是较轻,请设计算法找出这枚假币。
(1)用model记录真币。
(2)把硬币分成两堆,A堆和B堆,两堆的数量是相等的。计算两堆硬币各自的重量sumA和sumB。
(3)如果两堆重量sumA和sumB相等,则有可能有两种情况,第一种情况是没有假币(如硬币数量是偶数,则没有假币),第二种是两堆都有假币,但是假币的位置是唯一的(如n是奇数5:1 1 2 1 1,假币在中间,分的时候两边都有假币,直接返回中间位置),此时已经不需要再称重了,直接记录真币为第一个,返回中间位。
(4)如果数量不想等,那么我们可以假设中间的那个硬币是真的(当然我们不会记录为真,还需比较才知道真假),因为我们知道两个硬币堆的数量是一样的,而且知道数量是多少,此时我们用这个假设的真币的重量乘以A堆的数量(两堆数量一样,比一堆即可)得到重量sumC,如果sumA等于sumC,说明假设的这个币就是真币,假币在B堆,否则假币就在A堆,那么真币就在B堆里面,即可记录真币为B堆的第一个硬币。
(5)当数量减少到1或2时,比较方式和三分法相同,如果剩一个,则直接返回当前硬币,如果剩2个,则判断第一个是否是真币,不是就返回第一个,否则返回第二个。
分成的A、B两堆数量保持相等,且数量大于等于2的问题?
如果不大于等于2,那么第二步把A分成两堆的就不能完成了,只有一个硬币在比较,那是比不出结果的。
如果n是偶数,如8:
则A堆为A = coins[0,1,2,3]
B堆为B = coins[4,5,6,7]
如果n是奇数,如7:
则A堆为A = coins[0,1,2,3]
B堆为B = coins[3,4,5,6]
这样分就没有剩下的硬币了。
#include
using namespace std;
int weightSum(int *coins, int begin, int end);
int findBadCoinBinaryRecursion(int *coins, int begin, int end, int &model);
int findBadCoinBinaryIterate(int *coins, int length, int &model);
void findBadCoinBinaryTest();
int main() {
findBadCoinBinaryTest();
return 0;
}
int weightSum(int *coins,int begin,int end){
int sum = 0;
while(begin <= end){
sum += coins[begin];
begin++;
}
return sum;
}
int findBadCoinBinaryRecursion(int *coins, int begin, int end, int &model) {
int n = end - begin + 1;
if(n == 1) {
return begin;
}
else if(n == 2) {
return coins[begin] != model ? begin : end;
}
int mid = n / 2;
int left = (n % 2 == 0) ? mid - 1 : mid;
int right = mid ;
int sumA = weightSum(coins, begin, left + begin);
int sumB = weightSum(coins, right + begin, end);
if(sumA == sumB) {
model = coins[begin];
return mid + begin;
}
else if(sumA == (left + 1) * coins[begin]){
model = coins[begin];
return findBadCoinBinaryRecursion(coins, right + begin, end, model);
}
else {
model = coins[right + begin];
return findBadCoinBinaryRecursion(coins, begin, left + begin, model);
}
}
int findBadCoinBinaryIterate(int *coins, int length, int &model) {
int begin = 0;
int end = length - 1;
while(begin <= end) {
int n = end - begin + 1;
if(n == 1) {
return begin;
}
else if(n == 2) {
return coins[begin] != model ? begin : end;
}
int mid = n / 2;
int left = (n % 2 == 0) ? mid - 1 : mid;
int right = mid ;
int sumA = weightSum(coins, begin, left + begin);
int sumB = weightSum(coins, right + begin, end);
if(sumA == sumB) {
model = coins[begin];
return mid + begin;
}
else if(sumA == (left + 1) * coins[begin]){
model = coins[begin];
begin = right + begin;
}
else {
model = coins[right + begin];
end = left + begin;
}
}
return -1;
}
void findBadCoinBinaryTest() {
int contin = 1;
do {
system("cls");
int n = 0;
cout << "请输入硬币数量n(n > 3):";
cin >> n;
if(n < 3) {
cout << "你输入的硬币数量太少了!" << endl;
continue;
}
int *coins = new int[n];
cout << "请输入硬币的重量:";
for(int i = 0;i < n;i++) {
cin >> coins[i];
}
int model = -1;
int index = -1;
cout << "--------递归结果--------\n" << endl;
model = -1;
index = findBadCoinBinaryRecursion(coins, 0, n - 1, model);
if(coins[index] > model) {
cout << "第" << index + 1 << "个硬币是假的,比其他硬币重了!" << endl;
}
else if(coins[index] < model) {
cout << "第" << index + 1 << "个硬币是假的,比其他硬币轻了!" << endl;
}
else {
cout << "没有假币!" << endl;
}
cout << "\n--------迭代结果--------" << endl;
model = -1;
index = findBadCoinBinaryIterate(coins, n, model);
if(coins[index] > model) {
cout << "第" << index + 1 << "个硬币是假的,比其他硬币重了!" << endl;
}
else if(coins[index] < model) {
cout << "第" << index + 1 << "个硬币是假的,比其他硬币轻了!" << endl;
}
else {
cout << "没有假币!" << endl;
}
delete []coins;
cout << "继续检测输入1,退出输入0:";
cin >> contin;
} while (contin == 1);
cout << "欢迎再次检测!" << endl;
}
出问题了,改了,应该可以吧。