今天看了一篇博文創新工場面試題詳解題目:abcde五人打漁,打完睡覺,a先醒來,扔掉1條魚,把剩下的均分成5分,拿一份走了;b再醒來,也扔掉1條,把剩下的均分成5份,拿一份走了;然後cde都按上面的方法取魚。問他們一共打了多少條魚?
許多小朋友都參與其中,挺有意思,我看了一下參與者的答案,發現大多都是採用循環遍歷的方法,雖然能得到解,但不是正確的解題思路,這道題有簡單的數學解: X = 5^5 - (5-1);
該題目可以推廣到M個人,假設第一個人分魚前有X1條魚,第二個人分魚前有X2條魚.....第M個人分魚前有Xm條魚, 如果把魚的數量增加M-1條,每個人都可以均分後拿掉自己的一份(不用再扔掉一條了),這樣你可以導出:
X1 = M^M * Xm+1 / (M-1)^(M-1);
而 Xm+1 / (M-1)^(M-1) 的最小整數值爲1,因此 X1 = M^M 了,再減去添加的M-1條,就得到了答案。
但作爲編程題是在考你是否會使用遞歸算法.
根據題意可以得出如下公式:
X1- (X1-1)/M - 1 =X2 導出X1 = (M*X2+M-1)/(M-1), 進一步可以推到出Xn = (M*Xn-1+M-1)/(M-1)。
跟據題意還可以知道,最後一個人分完後,魚的數量是可以被M-1個人均分的 ,即Xm+1= (M-1)*k, k=1,2,3....爲>0的整數。這樣對於確定的M和k,Xm+1的值就是已知的,這樣就可以用遞歸法求解該題了。
這樣的解題效率是高的,對於M=5的情況,僅需255次循環就可以得到解 X1=3121.
爲了增加趣味性,本程序在得到解後,將X1 ~ Xm 都輸出出來了。
具體參見下面的代碼,該程序採用遞歸算法,不太好理解,請大家認真閱讀,遞歸程序是程序員的基本功啊。
不過這都是具體小玩意,小遊戲而已,要想成爲優秀的軟件工作者,還是要多學習編碼是設計方面的理論:參見http://blog.csdn.net/xabcdjon/article/details/6707050 和http://blog.csdn.net/xabcdjon/article/details/6823653
public class DisFish {
static int M = 5; //人的個數
static int N = 2; //希望得到幾個結果
static int result[] = new int[M];
public static void main(String[] args) throws Exception
{
int n = 0;
int k = 1;
while (n < N) {
int x1 = calculateX(2,k); //x1 = f(x2) x1是x2的函數。
if (x1>0) {
n++;
result[0]= x1;
outRes(k);
}
k++;
}
}
/**
* 遞歸求解 Xm-1 = (M*Xm+M-1)/(M-1)
* @param m
* @param k 試算的正整數
* @return 返回-1 表示整數k試算失敗,因爲剩餘的數量不能被M-1個人均分
*/
static int calculateX (int m,int k) {
int xm = -1;
if (m>M) {
int x = (M-1)*k;
xm = M*x / (M-1) + 1;
return xm;
}
int xplus = calculateX(m+1,k); //遞歸求解Xm+1
if (xplus<0) return -1;
int r = M*xplus%(M-1);
if (r!=0) return -1; //剩餘的數量不能被M-1個人均分
xm = M*xplus / (M-1) + 1;
result[m-1] = xm; //記錄Xm
return xm;
}
static void outRes(int k){
System.out.println(" k="+k);
for (int i = 0; i < result.length; i++) {
int p = i+1;
System.out.print("X"+p+"="+result[i]+" ");
}
System.out.println();
}
}
你也可以試着採用增加M-1條魚後的遞歸公式進行編程求解,加深一下對遞歸算法的掌握。