ACM —— 1006 Biorhythms

解題代碼:

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;


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章