標籤:acm 大數
今天給學弟學妹們講大數問題,自己又把大數問題好好的複習了一遍,用c重新實現了一下;除法還是有點複雜,有點沒搞清,所以就不誤人子弟了,把大數的加法,乘法,減法,階乘都自己寫了一遍,對大數問題又加深了一點,大精度的還是要慢慢的積累,java版本的上次已經寫了;加一個自己的傳送門;java寫真的是挺方便的啊;java大數
一些基礎資料型別 (Elementary Data Type)的範圍:
int:32位整數,佔4位元組,-2^31~2^31-1(-21億多~21億多)
unsigned int:佔4位元組,0~2^32-1(0~42億多) –10位元
VC的64位整數 :
__int64:佔8位元組,-2^63~2^63-1(-900億億多~900億億多)
unsigned __int64:佔8位元組,0~2^64-1(0~1800億億多)-20位元
G++的64位整數:
long long==__int64
unsigned long long==unsigned __int64
實數
float:佔4位元組,7位有效數字
double:佔8位元組,15位有效數字
浮點型的問題都是追求精度的,在一般情況下我們應當選擇使用double,而很少用float;
所以當我們要進行計算的數超過了20位,我們就要用數組來類比我們的計算過程了;
選取的是poj百練上的比較基礎的例題,從基礎的開始做,只要弄懂就好,積累自己的模板,再靈活運用;
2981:大整數加法 http://bailian.openjudge.cn/practice/2981
其實大整數的加法之類的,演算法都比較簡單,按照我們平時豎式計算的方式,用數組類比大數的加法,要注意的就是處理好之間的進位問題,然後其中的輸入輸出也要注意,轉化成我們習慣的那種方式去進行計算,輸出的時候要處理好前端零;
主要是要理解這種處理方式;
下面是代碼:代碼就是隨便寫一下的,還可以進行最佳化,並不是最簡的,能夠易於理解就好;
#include <cstdio>#include <cstring>char a[220],b[220];int c[220],d[220];int result[240];int main(){ int i=0,j=0,lena,lenb,n; gets(a);//把數字用字串儲存輸入 gets(b); memset(c,0,sizeof(c));//對數組進行初始化 memset(d,0,sizeof(d)); memset(result,0,sizeof(result)); lena=strlen(a); lenb=strlen(b); n=lena>lenb?lena:lenb; for(j=0,i=lena-1;i>=0;i--)//把字元數組倒序轉換到數字數組中(滿足我們的計算習慣) c[j++]=a[i]-'0'; for(j=0,i=lenb-1;i>=0;i--) d[j++]=b[i]-'0'; for(i=0;i<n;i++) { result[i]+=c[i]+d[i];//把兩個數組相加 if(result[i]>=10)//處理進位 { result[i+1]++; result[i]-=10; } } i=n; int flag=0; while(!result[i])//處理前端零 { if(i==0) { flag=1; printf("0"); } i--; } while(i>=0&&flag==0) { printf("%d",result[i]); i--; } printf("\n"); return 0;}
2980:大整數乘法 http://bailian.openjudge.cn/practice/2980
乘法和加法的思想基本上一致,這裡要注意的是,i和j位置相乘的結果要儲存在結果數組的i+j的位置;下面是代碼;
#include <cstdio>#include <cstring>char a[220],b[220];int c[220],d[220];int result[440];int main(){ int i=0,j=0,lena,lenb,n; gets(a);//把數字用字串儲存輸入 gets(b); memset(c,0,sizeof(c));//對數組進行初始化 memset(d,0,sizeof(d)); memset(result,0,sizeof(result)); lena=strlen(a); lenb=strlen(b); n=lena>lenb?lena:lenb; for(j=0,i=lena-1;i>=0;i--)//把字元數組倒序轉換到數字數組中(滿足我們的計算習慣) c[j++]=a[i]-'0'; for(j=0,i=lenb-1;i>=0;i--) d[j++]=b[i]-'0'; for(i=0;i<lena;i++) for(j=0;j<lenb;j++) result[i+j]+=c[i]*d[j];//i*j的結果要儲存在i+j的位置 for(i=0;i<n*2;i++) { if(result[i]>=10)//處理進位 { result[i+1]+=result[i]/10; result[i]%=10; } } i=n*2-1; while(result[i]==0) i--; //處理前端零 while(i>=0) { printf("%d",result[i]); i--; } return 0;}
2736:大整數減法 http://bailian.openjudge.cn/practice/2736
減法和加法的思想基本一致;把程式中的加法換成減法,進位處理的時候注意;
下面是代碼;
#include <cstdio>#include <cstring>int main(){ //freopen("1.txt","r",stdin); char a[220],b[220]; int c[220],d[220]; int result[240]; int n,i,j,lena,lenb; scanf("%d",&n); while(n--) { scanf("\n%s",a); getchar(); scanf("%s",b); memset(c,0,sizeof(c)); memset(d,0,sizeof(d)); memset(result,0,sizeof(result)); lena=strlen(a); lenb=strlen(b); for(i=lena-1,j=0;i>=0;i--) c[j++]=a[i]-'0'; for(i=lenb-1,j=0;i>=0;i--) d[j++]=b[i]-'0'; for(i=0;i<lena;i++) result[i]=c[i]-d[i]; for(i=0;i<lena;i++) if(result[i]<0)//處理小於零的情況 { result[i]+=10;//向前一位借10; result[i+1]--; } for(i=lena-1;!result[i]&&i>0;i--);//處理前端零 for(j=i;j>=0;j--) printf("%d",result[j]); printf("\n"); } return 0;}
大數階乘: http://acm.nyist.net/JudgeOnline/problem.php?pid=28
大數階乘這裡就相當於進行了多次乘法,這裡我是用的10000進位,基本思想也是一樣的;
下面是代碼:
#include <cstdio>#include <cmath>void factorial(int n){int a[10000];int i,j,c,m=0;a[0]=1;for(i=1;i<=n;i++){ c=0; for(j=0;j<=m;j++)//m表示的是當前數組的位元 { a[j]=a[j]*i+c; c=a[j]/10000;//判斷有沒有進位 a[j]=a[j]%10000; //儲存進位的數 } if(c>0) {m++;a[m]=c;}} printf("%d",a[m]); int w=m*4+log10(a[m])+1;//這裡是計算階乘的總位元 (這裡可以不要) for(i=m-1;i>=0;i--) printf("%0.4d",a[i]);//假如當前位置的數沒滿4位的話,在前補零 printf("\n"); printf("%d",w);//(也可以不要這個輸出)}int main(){ int m; while(scanf("%d",&m)!=EOF) { factorial(m); } return 0;}
大數除法還要自己去研究一下~研究好了再更新~
大數問題(合輯)