1. 程式人生 > 實用技巧 >瓶子和燃料(歐幾里得演算法)

瓶子和燃料(歐幾里得演算法)

瓶子和燃料

jyy就一直想著儘快回地球,可惜他飛船的燃料不夠了。 有一天他又去向火星人要燃料,這次火星人答應了,要jyy用飛船上的瓶子來換。jyy的飛船上共有 N個瓶子(1<=N<=1000) ,經過協商,火星人只要其中的K 個 。 jyy

將 K個瓶子交給火星人之後,火星人用它們裝一些燃料給 jyy。所有的瓶子都沒有刻度,只

在瓶口標註了容量,第i個瓶子的容量為Vi(Vi 為整數,並且滿足1<=Vi<=1000000000 ) 。

火星人比較吝嗇,他們並不會把所有的瓶子都裝滿燃料。他們拿到瓶子後,會跑到燃料

庫裡鼓搗一通,弄出一小點燃料來交差。jyy當然知道他們會來這一手,於是事先了解了火

星人鼓搗的具體內容。火星人在燃料庫裡只會做如下的3種操作:1、將某個瓶子裝滿燃料;

2、將某個瓶子中的燃料全部倒回燃料庫;3、將燃料從瓶子a倒向瓶子b,直到瓶子b滿

或者瓶子a空。燃料傾倒過程中的損耗可以忽略。火星人拿出的燃料,當然是這些操作能

得到的最小正體積。

jyy知道,對於不同的瓶子組合,火星人可能會被迫給出不同體積的燃料。jyy希望找

到最優的瓶子組合,使得火星人給出儘量多的燃料。

輸入格式

第1行:2個整數N,K,

第2..N 行:每行1個整數,第i+1 行的整數為Vi

輸出格式

僅1行,一個整數,表示火星人給出燃料的最大值。

資料範圍和提示

選擇第2 個瓶子和第 個瓶子,火星人被迫會給出4 體積的容量。

輸出時每行末尾的多餘空格,不影響答案正確性

樣例輸入

3 2 

3 

4 

4

樣例輸出

4 

思路:

裴蜀定理 對任何整數a、b和它們的最大公約 數d,關於未知數x和y的線性不定方程(稱為裴蜀等式):若a,b是整數,且gcd(a,b)=d,

那麼對於任意的整數x,y,ax+by都一定是d的倍數,特別地,一定存在整數x,y,使ax+by=d成立。

它的一個重要推論是:a,b互質的充要條件是存在整數x,y使ax+by=1.

我們來模擬一下火星人倒燃料的過程:

樣例:3 4 4

顯然只有兩種方案:3 4和4 4

3(①) 4(②):把②倒入燃料,然後倒給①,把①倒掉,於是乎,只剩下②的1單位燃料。

4 4:由於火星人會給你燃料,所以無論怎麼倒都會有一個瓶子有4單位燃料。

結論就顯而易見了,其實就是要從n個數找出k個數,使最大公約數最大。

程式碼:

#include<map>
#include<cstdio>
using namespace std;
int a[1010],p[5000010],t,ans;//a體積,f能裝x體積的個數,p燃料
map<int,int>f; 
int max(int x,int y){
    return x>y?x:y;
}
int read()//快讀根據自己需要酌情新增
{
    int x=0,y=1;char c=getchar();while(c<'0'||c>'9'){y=-y;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+(c-'0');c=getchar();}
    return x*y;
}
int main()
{
    int n=read(),k=read(),i,j;
    for(i=1;i<=n;i++)
    {
        a[i]=read();
        for(j=1;j*j<=a[i];j++)
        {
            if(a[i]%j!=0) continue;
            if(!f[j]) p[++t]=j;//第一次進入 
            f[j]++;//能裝的個數++ 
            if(!f[a[i]/j]) p[++t]=a[i]/j;//
            if(j*j!=a[i]) f[a[i]/j]++;//判相等 
        }
    }
    for(i=1;i<=t;i++)
    {
        if(f[p[i]]>=k) ans=max(ans,p[i]);//
    }
    printf("%d",ans);
    return 0;
;}