倒水
有兩個容器,容積分別為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); }
分析
經典的倒水問題,有不少公司也出了類似的面試題目,有的以選擇題形式出現,也有編程題形式出現的,下面做簡要的分析:
對題目做簡要的處理分析后,C升水是可以分多次倒入的,假設A > B,那么每次可以倒的水的量為A , B , (A + B) ,( A - B)升水,設置4個因子,分別為x1 , x2, x3, x4 , (x1 , x2, x3, x4 屬於整數),如果可以使得水缸最后恰好有C升水,那么必然存在整數x1 , x2, x3, x4,使得
Ax1 + Bx2 + (A + B)x3 + (A - B)x4 = C 等式成立;
對等式做一定的變換,得到公式
(x1 + x3 + x4)A + (x2 + x3 - x4)B = C ; --( 1-1 )
設 x = x1 + x3 + x4 , y = x2 + x3 - x4 , x, y 均為整數;最終得到公式
xA + yB = C ; --( 1-2 )
x1 , x2, x3, x4 可以假設為正整數,用幾個for循環可以實現,但是時間復雜度太大,為O(N4),題目中給的范圍是0 < A , B, C <= 1000000000;整數在十億范圍,顯然運行時間肯定會超過 3s ,不符合要求,那有沒有更加合適的方法呢,在算法的書里面,有一個算法,與公式( 1-2 ) 不謀而合,是擴展的歐幾里德算法,算法描述:
定理:

#include <stdio.h> #include <stdlib.h> //求最大公約數 int gcd(int a, int b) { int m = a, n = b , r = 1; while(1) { r = m % n; if(r == 0) { return n; } else { m = n; n = r; } } } //返回值1表示能使得水缸恰好有C升水,0表示不能 int can(int a,int b,int c) { int result = 0; result = gcd(a,b); if(c % result == 0 ) { return 1; } else { return 0; } } int main(void) { int A , B , C; A = 1234567; B = 7654321; C = 9999999; printf("the result is %d",can(A,B,C)); return 0; }
同樣,附帶幾個測試用例:
輸入:A = 1234567, B = 7654321 , C = 9999999, 輸出:result = 1;
輸入:A = 9999, B = 5555, C = 2222, 輸出:result = 1;
輸入:A = 1000000000, B = 2, C = 1 , 輸出:result = 0.
下面是做一個實例演示:假設A = 11 , B =39 , C = 2,返回值為1,說明可以實現,為方便敘述,采用A(11) , B(39)表示容器,步驟如下:
1、 將容器 B(39) 倒滿水,然后3次倒入 A(11) 容器中,那么 B(39) 剩下 39 - 11 * 3 = 6升水,此時A(11)可用;
2、 把 B(39) 中的 6 升水全部倒入容器 A(11) 中,那么容器 A(11) 中有 6 升水,5 升是空的,此時B(39)可用;
3、 把 B(39) 倒滿水,然后往第2步得到的 A(11 )倒入直到 A(11) 滿為止,那B(39)剩下 39 - 5 = 34 升水,清空 A(11) ,此時A(11)可用;
4、 步驟3得到的 B(39) 容器有34升水,3次倒入 A(11)中,那 B(39)中剩下 34 - 11 * 3= 1升水,此時 A(11)可用;
5、 把步驟4的 1 升水倒入水缸,清空 A(11) 和 B(39),重做步驟1 - 4,再往水缸倒入1升水,那水缸里就是 1 + 1 = 2 升水了。