經典問題----倒水


倒水

  有兩個容器,容積分別為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,  x, (x1 , x2, x3, x4 屬於整數),如果可以使得水缸最后恰好有C升水,那么必然存在整數x1 , x2, x3, x4,使得

          Ax1 + Bx2 +  (A + B)x3  + (A - B)x = C    等式成立;

  對等式做一定的變換,得到公式

          (x1 + x+ x4)A + (x2 + x- x4)B = C ;     --( 1-1 )

  設 x = x1 + x+ x, y = x2 + x- x4 ,  x, y 均為整數;最終得到公式

          xA + yB = C ;                                               --( 1-2 )       

   x1 ,  x2,  x3,  x4 可以假設為正整數,用幾個for循環可以實現,但是時間復雜度太大,為O(N4),題目中給的范圍是0 < A , B, C <= 1000000000;整數在十億范圍,顯然運行時間肯定會超過 3s ,不符合要求,那有沒有更加合適的方法呢,在算法的書里面,有一個算法,與公式( 1-2 ) 不謀而合,是擴展的歐幾里德算法,算法描述:

定理:

  對於不完全為 0 的非負整數 a,b,gcd(a,b)表示 a,b 的最大公約數,必然存在整數對 x,y ,使得 gcd(a,b)=ax+by.
  
  根據歐幾里德擴展算法,Gcd(A, B) = Ax + By,求出A和B的最大公約數,如果C能被最大公約數整除Gcd(A, B) 整除,那就可以實現水缸里恰好為C升水;
  那題目就直接轉換為求A 、B的最大公約數了,求公約數可以用輾轉相除法,代碼如下:
#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;
}
View Code

同樣,附帶幾個測試用例:

輸入: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 升水了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM