當前位置:首頁 » 操作系統 » 換零錢演算法

換零錢演算法

發布時間: 2024-07-18 01:44:27

『壹』 鑰冮橈細鐜嬪笀鍌呮槸鍗栭瀷鐨勶紝涓鍙岄瀷榪涗環30鍏冪敥鍗20鍏冿紝欏懼㈡潵涔伴瀷緇欎簡寮50錛岀帇甯堝倕娌¢浂閽憋紝浜庢槸鎵鵑偦灞呮崲浜50鍏

棣栧厛浣犲亣璁句綘鍙h嬫湁100鍏冮挶錛岃繘璐х殑鏃跺欏墿涓70鍏冿紙1寮20+1寮50錛夈傞【瀹㈡潵鐨勬椂鍊欙紝緇欎簡鐜嬪笀鍌呬竴寮50錛屾墍浠ョ幇鍦ㄦ槸錛20+50+50錛夈傜帇甯堝倕鎶婂畠鍏戞崲浜嗭紝鍙樻垚浜嗭紙20+50+10*5錛夈傚厬鎹浠ュ悗錛屾壘浜30鍏冮挶緇欓【瀹銆傜幇鍦ㄥ彉鎴愪簡錛20+50+10*2錛夊彂鐜版槸鍋囬挶浠ュ悗錛屽張灝戜簡50錛岀幇鍦ㄥ彉鎴愪簡錛20+10*2錛夈備篃灝辨槸璇村師鏈鐨100鍏冿紝鍙樻垚浜嗙幇鍦ㄧ殑40鍏冿紝鎵浠ュ叡浜忎簡60鍏冦
-------鏂規硶鉶界錛屼絾榪欐牱綆楃粷瀵規病閿欍
-------榪樻湁灝辨槸鐜嬪笀鍌呭師鏈鏄鎵撶畻浜忔湰10鍏冨嚭鍞鐨勶紝鐜板湪浜忔湰60鍏冿紝姣斿師璁炬兂澶氫簭鏈50鍏冿紝鎵浠ュ傛灉鐩存帴鍥炵瓟50鍏冨簲璇ヤ篃涓嶇畻閿
鍏跺疄綆鍗曟潵璇村氨鏄濡傛灉閭50鏄鐪熺殑錛岄偅灝變簭10鍏冿紝鐜板湪50鏄鍋囩殑錛屾墍浠ヤ簭60錛堜腑闂磋繃紼嬪畬鍏ㄤ笉鐢ㄨ冭檻錛

『貳』 演算法:找零錢,有4種硬幣1,2,5,10,將X和Y換成零錢,求所用的最少錢數 如:8,9,輸出4(1,2,2,5)

這個演算法相對較為簡單,使用大面值硬幣優先使用即可。
void getCoinList(int bigMoney)
{
int coinValues[] = {10, 5, 2, 1};
int coins[4] = {0};
int totalCoins = 0;
int surplusMoney = bigMoney;
int i = 0, j = 0;
for (i = 0; i < 4; i++)
{
coins[i] = surplusMoney / coinValues[i];
totalCoins += coins[i];
surplusMoney = bigMoney % coinValues[i];
}
printf("%d(", totalCoins);
for(i = 3; i >= 0; i--)
for(j = 0; j < coins[i]; j++)
{
if (--totalCoins > 0)
printf("%d ,", coinValues[i]);
else
printf("%d", coinValues[i]);
}
printf(")", coinValues[i]);
}

『叄』 100元換成10元5元1元紙幣,每種至少一張,一共多少換法

81種換法
一 ,每種至少一張,實際應為至少10元、5元各一張,1元的5張。共20元,剩下的80元可任意分配。
二,80元的零錢可以如下:
8張10元。1種
7張10元,5元的2、1、0張(差額為1元,下同)。3種
6張10元,5元的4、3、2、1、0張。5種
5張10元,5元的6、5、4、3、2、1、0張。7種
......
1張10元,5元的14、13.....6、5、4、3、2、1、0張。15種
0張10元,5元的16、15、14、13.....6、5、4、3、2、1、0張。17種
三,總的換法為
1+3+5+.....+15+17=81種
看到這個題目的第一感覺就是一個三元一次方程的求解,編程的話,就是三個for循環外加個if判斷,瞬間KO。對這個題目來說效率也是可以接受的。可是這根本沒有體現出演算法的優勢。下面我們來仔細推敲下這裡面隱藏的規律。 根據上圖的規律,即可得到如下代碼:

/**
* 1、求解特定實例:要將100元兌換為1元、5元、10元的零錢,請問有多少種兌換方法?
*
* @return
* @author chenchanghan
*/
public static int getDivideWays() {
int count = 0;
for (int i = 0, size = 100 / 10; i <= size; i++) {
// 針對10的每個場景,計算5的組合情況(即,從0個5 到 n( n=(100 - i * 10)/5
// )個5共n+1種情況
count += (100 - i * 10) / 5 + 1;
}
return count;
}

到這里,這個就算解完了,但是這里確實因為分解的元素中包含1,將問題變的簡單化了,如果不是1、5、10而是隨意的三個數字,改怎麼解決呢?同樣還是要找出規律來。

下面我們就來分析下10、5、3如何組合成100吧。

首先,0個10的情況下,5和3怎麼組合成100呢?正好20*5=100,顯然這是不存在10的情況下出現最多5的情況,那還有沒有其他的組合情況呢?這時我們就要用到一個最小公倍數(3和5的最小公倍數是15),很顯然,我們就可以將」3個5替換成5個3「了。因為最多20個5,所以我們可以繼續用」3個5替換成5個3「,直到最後剩下2個5。綜上0個10的情況下,5可以出現的次數分別為20、17、14、11、8、5、2,所以該場景下共有7中組合方式。

其次,1個10的情況下,5和3怎麼組合成100呢?我們還是從5來出發,5*18=90,1個10的情況下,組合成100,最多可以出現18次,同理還是用」3個5替換成5個3「。最終1個10的情況下,5可以出現的次數分別為18、15、12、9、6、3、0。該場景下也有7種組合方式。

同理,依次分析下去。

根據上面的規律,得出代碼如下:


/**
* 2、組合元素一般化:將total元兌換為large元、middle元、small元的零錢,請問有多少種兌換方法?
*
* @param total
* @param large
* @param middle
* @param small
* @return
* @author chenchanghan
*/
public static int getDivideWays(int total, int large, int middle, int small) {
if (total > 0 && small > 0 && middle > small && large > middle) {
int count = 0;
int LCM = getLeastCommonMutiple(middle, small);
int substituteUnit = LCM / middle;
for (int i = 0, size = total / large; i <= size; i++) {
int restTotal = total - i * large;
if (restTotal > 0) {
// actualMaxMiddleNum>=0,表示restTotal正好可以有x個middle和y個small拼湊起來(x、y是大於等於0的整數)
int actualMaxMiddleNum = getActualMaxMiddleNum(restTotal, middle, small);
if (actualMaxMiddleNum >= substituteUnit) {
// actualMaxMiddleNum >=substituteUnit,表示可以將substituteUnit個middle替換成LCM/small個small
// 可以換多少次呢?顯然可以換0、1...actualMaxMiddleNum/substituteUnit,即:actualMaxMiddleNum/substituteUnit+1
count += actualMaxMiddleNum / substituteUnit + 1;
} else if (actualMaxMiddleNum >= 0) {
// 0<=actualMaxMiddleNum// 因為count++;
}
} else {
// 正好被large完美匹配了
count++;
}
}
return count;
} else {
throw new IllegalArgumentException();
}
}

/**
* 獲得方程:x*middle + y*small = restTotal 中x最大的取值。
*
* @param restTotal
* @param middle
* @param small
* @return
* @author chenchanghan
*/
private static int getActualMaxMiddleNum(int restTotal, int middle, int small) {
int modMiddle = restTotal % middle;
int maxMiddleNum = restTotal / middle;
int actualMaxMiddleNum = -1;
if (modMiddle == 0 || modMiddle == small) {
actualMaxMiddleNum = maxMiddleNum;
} else {
// 無法使用最大數量(即:maxMiddleNum)的middle和small組合成restTotal,
// 則需要逐步減少middle的個數,進而增加small的個數,來嘗試組合成restTotal。
int minusMiddleNum = getMinusMiddleNum(middle, small, modMiddle, maxMiddleNum);
if (minusMiddleNum > 0) {
// 表示可以形成一個擁有最大middle數的組合,即: (maxMiddleNum - minusMiddleNum)*middle + y*small = restTotal ;
actualMaxMiddleNum = maxMiddleNum - minusMiddleNum;
} else {
// middle和small無論怎麼組合都無法拼湊成restTotal,即:x*middle + y*small = restTotal 的整數解不存在
actualMaxMiddleNum = -1;
}
}
return actualMaxMiddleNum;
}

/**
*
* @param middle
* @param small
* @param modMiddle
* @param maxMiddleNum
* @return
* @author chenchanghan
*/
private static int getMinusMiddleNum(int middle, int small, int modMiddle, int maxMiddleNum) {
int minusMiddleNum = -1;
for (int i = 1; i <= maxMiddleNum; i++) {
if ((middle * i + modMiddle) % small == 0) {
minusMiddleNum = i;
break;
}
}
return minusMiddleNum;
}

/**
* 求兩個數的最小公倍數。
*
* @param middle
* @param small
* @return
* @author chenchanghan
*/
private static int getLeastCommonMutiple(int m, int n) {
return m * n / getGreatestDivisor(m, n);
}

/**
* 求兩個數的最大公約數。
*
* @param m
* @param n
* @return
* @author chenchanghan
*/
private static int getGreatestDivisor(int m, int n) {
int tmp = 0;
if (m < n) {
tmp = m;
m = n;
n = tmp;
}
while ((tmp = m % n) != 0) {
m = n;
n = tmp;
}
return n;
}我們再來推廣下,將分解的元素變成3個以上,具體見如下代碼:

/**
* 3、元素個數一般化:將total元兌換為a元、b元、c元、....的零錢,請問有多少種兌換方法?
*
* @param total
* @param elements
* @return
* @author chenchanghan
*/
public static int getDivideWays(int total,int[] elements){
if(elements!=null && elements.length>=3){
int count = 0 ;
if(elements.length == 3){
count += getDivideWays(total,elements[0],elements[1],elements[2]);
}else{
int large = elements[0];
int[] subElements = new int[elements.length-1];
System.array(elements, 1, subElements, 0, subElements.length);
for (int i = 0, size = total / large; i <= size; i++) {
int restTotal = total - i * large;
if (restTotal != 0) {
count += getDivideWays(restTotal, subElements);
} else {
count++;
}
}
}
return count ;
}else{
throw new IllegalArgumentException();
}
}

『肆』 2014楂樿冩暟瀛﹂:鍗栭瀷鐨勶紝涓鍙岄瀷榪涗環30鍏冪敥鍗20鍏冿紝欏懼㈡潵涔伴瀷緇欎簡寮50錛岀帇甯堝倕娌¢浂閽憋紝浜庢槸鎵

浠庡瓧闈涓婄湅鍍忔槸浜忎簡90鍏冿紝鍏跺疄鏄閿欑殑錛岃鏂囧瓧娣鋒穯浜嗭紝姝g『絳旀堟槸60鍏冦傚叾瀹為兘涓嶇敤鍘諱簤杈60銆90鍏冿紝浠婂ぉ鎴戝氨鎸夋爣鍑嗙殑浜ゆ槗嫻佺▼錛堜粠榪涜揣鍒版渶鍚庡埄娑︾泩浜忥級緇欏ぇ瀹惰︾粏瑙i噴姝g『鐨勭瓟妗堬紝鍥捐В濡備笅錛

熱點內容
白加黑源碼 發布:2024-11-25 23:48:25 瀏覽:388
上傳的壁紙 發布:2024-11-25 23:47:47 瀏覽:569
如何刪除緩存的視頻 發布:2024-11-25 23:44:54 瀏覽:435
編寫刷課腳本 發布:2024-11-25 23:43:20 瀏覽:869
php圖片緩存 發布:2024-11-25 23:41:36 瀏覽:953
android獲取sd卡文件 發布:2024-11-25 23:39:34 瀏覽:151
銀線存儲 發布:2024-11-25 23:37:44 瀏覽:624
教孩子學編程python 發布:2024-11-25 23:31:05 瀏覽:912
如何開啟伺服器埠8008 發布:2024-11-25 23:30:27 瀏覽:806
python字典中文key 發布:2024-11-25 23:30:11 瀏覽:997