洛谷1080-國王遊戲(深入理解高精度乘 除)
阿新 • • 發佈:2018-12-15
這個題目的解析可以檢視洛谷上的解析,我想寫的是有關這個題目中的高精度問題。
#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]
具體的實現方法和細節在程式碼中展示了,請仔細閱讀程式碼然後自己寫出來。