解題代碼:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner stdin = new Scanner(System.in);
int p,e,i,d,n;
int num = 0;
while (((p = stdin.nextInt()) != -1)
&& ((e = stdin.nextInt()) != -1)
&& ((i = stdin.nextInt()) != -1)
&& ((d = stdin.nextInt()) != -1)) {
n = (5544*p+14421*e+1288*i-d+21252)%21252;
System.out.printf("Case %d: the next triple peak occurs in %d days.%n", ++num, ((n == 0) ? 21252:n));
}
}
}
中國剩餘定理,本題難點不在編程,而是分析題目並轉化爲數學公式
要引入本題解法,先來看一個故事 “韓信點兵”:
傳說西漢大將韓信,由於比較年輕,開始他的部下對他不很佩服。有一次閱兵時,韓信要求士兵分三路縱隊,結果末尾多2人,改成五路縱隊,結果末 尾多3人,再改成七路縱隊,結果又餘下2人,後來下級軍官向他報告共有士兵2395人,韓信立即笑笑說不對(因2395除以3餘數是1,不是2),由於已 經知道士兵總人數在2300~2400之間,所以韓信根據23,128,233,------,每相鄰兩數的間隔是105(3、5、7的最小公倍數),便 立即說出實際人數應是2333人(因2333=128+20χ105+105,它除以3餘2,除以5餘3,除以7餘2)。這樣使下級軍官十分敬佩,這就是
韓信點兵的故事。
韓信點兵問題簡化:已知 n%3=2, n%5=3, n%7=2, 求n。
再看我們這道題,讀入p,e,i,d 4個整數
已知(n+d)%23=p; (n+d)%28=e; (n+d)%33=i ,求n 。
兩道題是一樣的。但是韓信當時計算出結果的?
韓信用的就是“中國剩餘定理”,《孫子算經》中早有計算方法,大家可以查閱相關資料。
“韓信點兵”問題計算如下:
因爲n%3=2, n%5=3, n%7=2
我們先找一個最小的數能被5和7整除,並且除以3的餘數爲1,這裏,我們可以找到最小的數是70。有什麼好處呢,大家知道70 * 1 % 3 = 1,那麼70 * 2 % 3 = 2,70 * a % 3 = a,這樣可以方便找到140這個除以3餘數又爲2的數,同時又能被5和7整除。
同理,我們可以找到21是能被3和7整除但是除以5餘數是1的數,那麼63便是除以5餘數是3. 15能被3和5整除,但是除以7餘數是1,那麼30便是除以7餘數是2的數。
那麼 140 + 63 + 30 = 233,必定是一個除以3餘數是2,除以5餘數是3,除以7餘數是2的一個數,而我們又很容易知道233加上或者減去3,5,7的最小公倍數,得到的數同樣滿足這個性質。韓信已知士兵人數在2300~2400之間,所以只需要233 + i × lcm(3,5,7)= 233 + 105 * 20 = 2333.
同樣,這道題的解法就是:
假設過n天后,三個生理週期同時到高峯。
已知(n+d)%23=p; (n+d)%28=e; (n+d)%33=i
使33×28×a被23除餘1,用33×28×8=5544;
使23×33×b被28除餘1,用23×33×19=14421;
使23×28×c被33除餘1,用23×28×2=1288。
因此有(5544×p+14421×e+1288×i)% lcm(23,28,33) =n+d
又23、28、33互質,即lcm(23,28,33)= 21252;
所以有n=(5544×p+14421×e+1288×i-d)%21252
本題所求的是最小整數解,避免n爲負,因此最後結果爲n= [n+21252]% 21252
那麼最終求解n的表達式就是:
n=(5544*p+14421*e+1288*i-d+21252)%21252;