問題描述
有八枚銀幣a b c d e f g h ,已知其中一枚是假幣,其重量不一樣於真幣,不知是較輕或較重,如何使用天平以最少的比較次數,肯定此枚假幣和輕重.算法
算法思路
由於要求以最少的比較次數肯定假幣和輕重,則咱們不能使用暴力破解此類的方法.咱們能夠用決策樹(decision tree)幫助分析與求解.思路是,將八枚硬幣分紅2份3個,對相應分法進行比較並取相應分法裏比較的最少次數.
其中一種簡單情況是,分紅2份3個.兩份是a+b+c和d+e+f.若是比較二者相等,則假幣在g和h裏,比較g和h,若是g比h重(或輕),再比較g和a(a是真幣),若是g比a重,則g是重假幣.ui
算法展現(代碼已註釋)
- 參數設置
void compare(int[], int, int, int);
void eightcoins(int[]);
void coins() {
int coins[8] = {3,3,3,3,4,3,3,3};
int i;
eightcoins(coins);
printf("\n列出全部錢幣的重量:");
for (i = 0; i < 8; i++)
{
printf("%3d", coins[i]);
}
printf("\n");
}
複製代碼
- 主要算法
//若0,1,2和3,4,5相同,則7,6其中有一個是假幣
if (coins[0] + coins[1] + coins[2] ==
coins[3] + coins[4] + coins[5])
{
if (coins[6] > coins[7])
{
compare(coins, 6, 7, 0);
}
else
{
compare(coins, 7, 6, 0);
}
}
//若0,1,2比3,4,5重,則6,7爲真幣
else if (coins[0] + coins[1] + coins[2] >
coins[3] + coins[4] + coins[5])
{
//若0,3和1,4同樣重,則2,5其中有一個假幣
if (coins[0]+ coins[3]== coins[1]+coins[4])
{
compare(coins, 2, 5, 7);
}
//若0,3比1,4重,因爲1,2,3比4,5,6重且只有一個假幣,由於3,1左右變換並未影響輕重.則0,4中有一個是假幣
else if (coins[0] + coins[3] > coins[1] + coins[4])
{
compare(coins, 0, 4, 7);
}
//若0,3比1,4輕,因爲1,2,3比4,5,6重且只有一個假幣,1,3變換位置致使輕重變化,則1,3有一個是假幣
else if (coins[0] + coins[3] < coins[1] + coins[4])
{
compare(coins, 1, 3, 7);
}
}
//若1,2,3比4,5,6輕.則7,8是真幣
else if (coins[0] + coins[1] + coins[2] <
coins[3] + coins[4] + coins[5])
{
//若1,4和2,5相同,則3,6有一個是假幣
if (coins[0] + coins[3] == coins[1] + coins[4])
{
compare(coins, 5, 2, 0);
}
//若1,4比2,5重,3,1調換位置致使關係變化,則3,1中有一是假幣
else if (coins[0] + coins[3] > coins[1] + coins[4])
{
compare(coins, 3, 1, 0);
}
//若1,4比2,5輕,3,1調換位置爲形成變化,則0,4有一個是假幣
else if (coins[0] + coins[3] < coins[1] + coins[4])
{
compare(coins, 4, 0, 1);
}
}
複製代碼
- 完整展現
#include <stdio.h>
#include <stdlib.h>
//silver coins - 八枚銀幣
void compare(int[], int, int, int);
void eightcoins(int[]);
void coins() {
int coins[8] = {3,3,3,3,4,3,3,3};
int i;
eightcoins(coins);
printf("\n列出全部錢幣的重量:");
for (i = 0; i < 8; i++)
{
printf("%3d", coins[i]);
}
printf("\n");
}
void compare(int coins[], int i, int j, int k) {
if (coins[i] > coins[k])
{
printf("\n假幣 %d 較重,重%d", i + 1,coins[i]);
}
else
{
printf("\n假幣 %d 較輕,輕%d", j + 1,coins[j]);
}
}
void eightcoins(int coins[]) {
//若0,1,2和3,4,5相同,則7,6其中有一個是假幣
if (coins[0] + coins[1] + coins[2] ==
coins[3] + coins[4] + coins[5])
{
if (coins[6] > coins[7])
{
compare(coins, 6, 7, 0);
}
else
{
compare(coins, 7, 6, 0);
}
}
//若0,1,2比3,4,5重,則6,7爲真幣
else if (coins[0] + coins[1] + coins[2] >
coins[3] + coins[4] + coins[5])
{
//若0,3和1,4同樣重,則2,5其中有一個假幣
if (coins[0]+ coins[3]== coins[1]+coins[4])
{
compare(coins, 2, 5, 7);
}
//若0,3比1,4重,因爲1,2,3比4,5,6重且只有一個假幣,由於3,1左右變換並未影響輕重.則0,4中有一個是假幣
else if (coins[0] + coins[3] > coins[1] + coins[4])
{
compare(coins, 0, 4, 7);
}
//若0,3比1,4輕,因爲1,2,3比4,5,6重且只有一個假幣,1,3變換位置致使輕重變化,則1,3有一個是假幣
else if (coins[0] + coins[3] < coins[1] + coins[4])
{
compare(coins, 1, 3, 7);
}
}
//若1,2,3比4,5,6輕.則7,8是真幣
else if (coins[0] + coins[1] + coins[2] <
coins[3] + coins[4] + coins[5])
{
//若1,4和2,5相同,則3,6有一個是假幣
if (coins[0] + coins[3] == coins[1] + coins[4])
{
compare(coins, 5, 2, 0);
}
//若1,4比2,5重,3,1調換位置致使關係變化,則3,1中有一是假幣
else if (coins[0] + coins[3] > coins[1] + coins[4])
{
compare(coins, 3, 1, 0);
}
//若1,4比2,5輕,3,1調換位置爲形成變化,則0,4有一個是假幣
else if (coins[0] + coins[3] < coins[1] + coins[4])
{
compare(coins, 4, 0, 1);
}
}
}
int main(void) {
coins();
return 0;
}
複製代碼
算法描述
算法 | 時間複雜度 | 空間複雜度 |
---|---|---|
coins | O(n) | S(n) |
compare | O(1) | S(1) |
eightcoins | O(1) | S(1) |
總和 | O(n) | (n) |