1. 程式人生 > >洛谷1080-國王遊戲(深入理解高精度乘 除)

洛谷1080-國王遊戲(深入理解高精度乘 除)

這個題目的解析可以檢視洛谷上的解析,我想寫的是有關這個題目中的高精度問題。  

#include<bits/stdc++.h>
using namespace std;
const int maxn=1010;
const int maxm=1000000;
struct data
{
    int a,b;
} p[maxn];
int t[maxm];  ///第一位應該是所表示的大整數的位數也就是t[0],從第一位開始才是整數的每一位 依次從小到大排列,也就是105在陣列中表示成501
int d[maxm];  ///d陣列是中間做儲存轉換的作用,第一位仍然是整數位數
int ans[maxm];
int n;

bool Comp(data x,data y)
{
    return x.a*x.b<y.a*y.b;
}

void Times(int *X,int v,int *Y)  ///高精度乘法 是從最低位開始的,可以看做是模擬乘法運算
{
    int len=X[0];
    for (int i=1; i<=len+20; i++) Y[i]=0;
    for (int i=1; i<=len; i++) ///通過使x陣列中的每一位與v相乘,%10,只取乘積的最後一位,/10加到下一位
    {
        Y[i]+=(X[i]*v);
        Y[i+1]+=(Y[i]/10);
        Y[i]%=10;
    }
    while (Y[len+1]>0)
    {
        len++;
        Y[len+1]+=(Y[len]/10);
        Y[len]%=10;
    }
    Y[0]=len;
}

void Div(int *X,int v,int *Y)  ///高精度除法
{
    int len=X[0];
    int rest=0;
    for (int i=len; i>=1; i--) ///這裡注意:是從len開始的,也就是從整數的最大位開始的,可以看做模擬除法運算
    {
        rest=rest*10+X[i];
        Y[i]=rest/v;
        rest-=(v*Y[i]);  ///這裡相當於是除法當中的取餘數,和rest=rest*10+X[i]; 聯絡起來,就是一套完整的除法模擬
    }
    while (!Y[len]) len--;  ///這裡有點繞,例如 運算出來Y陣列數7000,可實際結果只是7,這一步是去除0操作
    if (!len) len=1;   ///倘若結果就是0000,上一步會把所有的0都去除,len會變成了0,這裡就是避免這種情況,使len=1
    Y[0]=len;
}

void Get_max(int *X,int *Y)   ///大整數的比較函式
{
    if (Y[0]<X[0]) return;   ///先比較各自的位數,x[0],y[0]
    if (Y[0]==X[0])
        for (int i=Y[0]; i>=1; i--)
            if (Y[i]<X[i]) return;
            else if (Y[i]>X[i]) break;
    for (int i=0; i<=Y[0]; i++) X[i]=Y[i];  ///若Y大則把Y賦值給x
}

int main()
{
    scanf("%d",&n);
    for (int i=0; i<=n; i++) scanf("%d%d",&p[i].a,&p[i].b);
    sort(p+1,p+n+1,Comp);

    t[0]=1;
    t[1]=1;
    for (int i=1; i<=n; i++)
    {
        Times(t,p[i-1].a,d);
        for (int j=0; j<=d[0]; j++) t[j]=d[j];
        Div(t,p[i].b,d);
        Get_max(ans,d);
    }
    for (int i=ans[0]; i>=1; i--)
        printf("%d",ans[i]);  
    printf("\n");
    return 0;
}

這裡的關鍵就是 Times()和Div()函式,一個是大整數的乘法,一個是大整數的除法運算。

大整數乘法運算Times():

           從最低那一位開始每一位乘以v,然後做/10和%10運算。

大整數除法運算Div():

           從最高那一位開始,每一項都試除以v,不夠除則商0,然後*10+下一項。

這是總的思路,還需要注意的是乘法和除法始終是圍繞x[],y[]展開的,它們的第0號元素都是指的這個陣列代表的整數的位數。並且都是最低位在最前,依次列推直到最高位。

在大數乘法運算中,是從最低位開始一直到最高位,也就是從x[1]~x[len]

在大數除法運算中,是從最高位開始一直到最低位,也就是從x[len]~x[1]

具體的實現方法和細節在程式碼中展示了,請仔細閱讀程式碼然後自己寫出來。