題目要求
有兩個容器,容積分別為A升和B升,有無限多的水,現在需要C升水。
我們還有一個足夠大的水缸,足夠容納C升水。起初它是空的,我們只能往水缸里倒入水,而不能倒出。
可以進行的操作是:
把一個容器灌滿;
把一個容器清空(容器里剩余的水全部倒掉,或者倒入水缸);
用一個容器的水倒入另外一個容器,直到倒出水的容器空或者倒入水的容器滿。
問是否能夠通過有限次操作,使得水缸最后恰好有C升水。
輸入:三個整數A, B, C,其中 0 < A , B, C <= 1000000000
輸出:0或1,表示能否達到要求。
函數頭部:
c語言:1表示可以,0表示不可以
int can(int a,int b,int c);
c++語言: true表示可以,false表示不可以
bool can(int a,int b,int c);
java語言:true表示可以,false表示不可以
public class Main {
public static boolean can(int a,int b,int c);
}
解題思路
這是一個典型的倒水問題/量水問題,使用歐幾里得算法就可解出來。
這里有一篇文章給出了簡單的倒水問題的解法,可以解決筆試面試里面一些簡單的填空題,可以看一看:
http://blog.csdn.net/morewindows/article/details/7481851
基本思想是:不斷用小桶裝水倒入大桶,大桶滿了立即清空,每次判斷下二個桶中水的容量是否等於指定容量。也就是用小桶容量的倍數對大桶的容量進行取余,直到余數等於指定容量。
例如,用7升的桶和11升的桶得到2升水可以這樣做:
7 % 11 = 7
14 % 11 = 3
21 % 11 = 10
28 % 11 = 6
35 % 11 = 2 成功得到2升水。
7 % 11 = 7
14 % 11 = 3
21 % 11 = 10
28 % 11 = 6
35 % 11 = 2 成功得到2升水。
對於明確說明可以得到xx升水,需要我們給出如何倒出來的步驟,可以用這個方法,很快捷。但是這個方法不適合解這道題。
歐幾里德算法又稱輾轉相除法,用於計算兩個正整數a,b的最大公約數。
用gcd(a,b) 表示a, b的最大公約數,則有定理:gcd(a,b) = gcd(b,a mod b) (a>b 且a mod b 不為0)
具體的算法實現有循環和遞歸兩種,我用的是循環的方法。
擴展歐幾里得算法
定理:對於不完全為 0 的非負整數 a,b,gcd(a, b)表示 a, b 的最大公約數,必然存在整數對 x, y ,使得 gcd(a,b)=ax+by。
定理:對於不完全為 0 的非負整數 a,b,gcd(a, b)表示 a, b 的最大公約數,必然存在整數對 x, y ,使得 gcd(a,b)=ax+by。
本題實際上是問是否存在整數x, y,使得ax+by=c成立。
如果c可以被gcd(a,b)整除,則成立。
因此解題步驟如下:
1. 求出gcd(a,b)
2. 判斷c是否能被gcd(a,b)整除,若能則返回true,否則返回false
2. 判斷c是否能被gcd(a,b)整除,若能則返回true,否則返回false
Java代碼
1 public static boolean can(int a,int b,int c) { 2 int r; 3 while (true) { 4 r = a % b; 5 if (r != 0) { 6 a = b; 7 b = r; 8 } else { 9 break; 10 } 11 } 12 return c%b == 0; //b現在是最大公約數,若c能被b整除,則可以 13 }