51nod基础题感触(1005大数加法)
Posted memocean
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了51nod基础题感触(1005大数加法)相关的知识,希望对你有一定的参考价值。
这篇就作为算法学习这块的第一篇文章啦!之前一直想来写一下博客来着,但是自己太懒了,建模比赛后想多休息(玩)一会儿(很长时间),一直没写。最近总算是下定决定了!
“的确是要开始写一写最近自己做题的感受了!”(超认真的!)
直入正题!(由于才正式开始学习,理解有不足之处还请指正!)
首先,遇到这样的题,如果不限制语言的话,抱着能快则快的心态,我们就用强大的Python就行了。实现起来也是十分地的简单,在这里,我就直接上代码啦!(这里我用的是Python3.6)
a=input()#输入,这时候的a实际上还是字符串 b=input() print(int(a)+int(b))#字符串转整形,进行加法运算
这样来看,Python在处理大数方面真地很方便,如果条件允许,推荐用Python来解题。但是,凡是还是要“知其然,更知其所以然”呀!所以这里我就依着我个人看资料后的个人理解用C++为大家讲一下吧!
我们的任务就是完成这样一个式子的计算
那么,我们大数要怎么计算呢?
这里我们先从简单的情况出发——两个非负数相加。
对此,我分为这样几个步骤:
1)正向数组存储 2)反向切割转化 3)逐位相加 4)反向输出
1)正向数组存储
为了方便讲解,我们以数12356611(A)、48661613(B)为例。(实际的int的范围可以去百度了解下,这里我们假设这时候整形就爆了!:P)
录入之后char数组的情况就是这样的,这里我们用str1承接A,str2承接B,A对应的位数为A_len,B对应的位数为B_len。
2)反向切割转化
得到str1、str2后,我们再将他们反向录入足够长的int数组中
3)逐位相加
我们需要由低位至高位逐项相加,并且,在计算的时候我们还需要设定一个变量CF来储存上次的进位信息,拿图中的例子来说:首先我们先让A[0]、B[0]相加,得到最开始的C[0],然后用语句CF = C[0]/10得到CF的进位值0,用语句C[0] =C[0]%10得到C[0]的值,然后,我们继续计算,让A[1]、B[1]与CF一同相加,我们得到了最开始的C[1],接着按照老办法,CF = C[1]/10得到新的CF,C[1] = C[1]%10……如此循环,直到计算到i = max(A_len,B_len) ,也就是说计算到“ 最大和数位数 + 1 ”的位。
另外,这里还要注明一下的是C[i] 是预先初始化为0的!承接str1、str2的整形数组A、B也是经过初始化为0才能接受str1、str2的。
4)反向输出
在这里,我们只需要“正确”反向输出经过处理的C数组内的内容就行了!虽然这段话看起来简单,但是想“正确输出”,没接触过的小白写程序的时候还是要多注意下这个问题——C的最高位在哪里?看到这个问题,如果不加思考,很容易就会写成“这还不简单?开头不就是很多0吗?从第max(A_len,B_len) + 1位开始,遇0不输出”。好了,这下可能该丢的0、不该丢的0都丢了。正确的想法应该是在前者的基础上改成“开始遇0不输出,但一遇到非0就停下来,然后找到了最高位的位置,按情况输出”。如果想更快点,可以就在计算和的时候给最后的逐位计算来个CF的特判,直接找到最高位。
了解了两个非负数相加,我们再考虑更复杂的情况——两个整数相加。
两个整数相加,情况一共有三种:两非负数相加;一非负、一负相加;两负相加。再想一想,两负数相加实际上就是两负数的绝对值相加再加上负号,而一非负、一负相加实际上就是先判断符号,再计算两数相减的绝对值,所以计算的模式实际上就是两种:非负数相加模式(也就是之前说的简单情况),非负数相减模式(新增的哦!)。
接下来,继续分析大数非负数相减。这里我们的思路与非负数大数相加类似,但是还是有区别的!过程分为这样几步:
1)正向数组存储 2)反向切割转化 3)结果符号判断 4)逐位相减 5)反向输出
在这里,为了有助于理解,我们用 1115545(A)、-1253564(B) 来进行讲解
1)正向数组存储
我们用str1、str2分别存储A、B。
2)反向切割转化
这里我们根据str1、str2中有无负号得到A、B的位数,它们分别为A_len,B_len。
3)结果符号判断
对于符号的判断,我们可以根据下方的伪代码来进行判断
if(A_len!= B_len) if(A_len>B_len) //A的长度大于B,A为正数,所以结果为正数,下接A-B大数减法 else int flag=0; int i=A_len-1; for(;i>0;i--) if(A[i]>B[i]) flag=1;//A比B大 if(i<0) 输出0; return 0; if(flag) //A-B>0,下接A-B大数减法 else //A-B<0,下接B-A大数减法
4)逐位相减
这里,与小学数学减法计算类似,我们从低位开始向高位计算,同时用br存储借位信息,用于后续的计算。
万事俱备,我们从 i=A_len - 1 开始计算。开始的时候,用A[6] - B[6]得到初始的C[6],然后检测C[6]是否小于0,结果不是,然后确定初始C[6]就是我们要求的C[6],继续计算C[5],同样的方法,我们得到C[5]为-1,我们发现C[5]是小于0的,所以需要借位,让C[4]减1,同时再让初始C[5]+10,得到的结果为9,接着继续计算,直到算出C[0]。同时,我们在计算的时候用一个整型变量rec记录不为零的位的下标,直到记录到最后一个非零位下标。
经过计算,我们得到如下结果。
5)反向输出
根据“结果符号判断”得出的结论进行符号输出,从下标为rec的C的数组元素开始逐个输出。
附C++代码:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int main () int a[10005]=0,b[10005]=0,c[10005]=0,la,lb,lc,x=0,nega=0,add=0,flag=0,bigger=1; //数组a,b代表被加数 c代表和数 char a1[10005],b1[10005]; //方便输入以及进行倒序用 gets(a1); gets(b1); if(a1[0]==‘-‘||b1[0]==‘-‘)//至少有一个为负 if(a1[0]==‘-‘&&b1[0]==‘-‘)//均为负 nega=1; //均为负数标志 add=1; //类同两非负数相加 la=strlen(a1)-1; lb=strlen(b1)-1; else //一个为负 flag=1; add=0; //类同两非负数相减 else if(a1[0]==‘0‘&&b1[0]==‘0‘) //均为0 cout<<0; else //均为非负 la=strlen(a1); lb=strlen(b1); for(int i=0;i<=la-1;i++) //进行倒序a a[la-i]=a1[i]-‘0‘; for (int j=0;j<=lb-1;j++) //进行倒序b b[lb-j]=b1[j]-‘0‘; lc=1; while(lc<=la||lc<=lb) //进行加法进位 c[lc]=a[lc]+b[lc]+x; x=c[lc]/10; c[lc]%=10; lc++; c[lc]=x; while(c[lc]==0) //确定最高位 lc--; for(int k=lc;k>=1;k--) //注意存放在数组中的数是倒序的 cout<<c[k]; return 0; if(nega==1&&add==1)//均为负数 for(int i=0;i<=la-1;i++) //进行倒序a a[la-i]=a1[i+1]-‘0‘; //cout<<la-i<<" "<<a[la-i]<<"||"; //cout<<endl; for (int j=0;j<=lb-1;j++) //进行倒序b b[lb-j]=b1[j+1]-‘0‘; //cout<<lb-j<<" "<<b[lb-j]<<"||"; //cout<<endl; lc=1; while(lc<=la||lc<=lb) //进行加法进位 c[lc]=a[lc]+b[lc]+x; x=c[lc]/10; c[lc]%=10; //cout<<lc<<" "<<c[lc]<<"||"<<endl; lc++; c[lc]=x; while(c[lc]==0) //注意最高位为0要舍弃 lc--; cout<<‘-‘; for(int k=lc;k>=1;k--) //注意存放在数组中的数是倒序的 cout<<c[k]; if(flag==1&&add==0) if(a1[0]==‘-‘) //a为负,b为正 int rec=0; la=strlen(a1)-1; lb=strlen(b1); for(int i=0;i<=la-1;i++) //进行倒序A a[la-i]=a1[i+1]-‘0‘; // cout<<la-i<<" "<<a[la-i]<<"||"; //cout<<endl; for (int j=0;j<=lb-1;j++) //进行倒序B b[lb-j]=b1[j]-‘0‘; // cout<<lb-j<<" "<<b[lb-j]<<"||"; //cout<<endl; if(la>lb) bigger=0; //|a|大 else if(la<lb) bigger=1; //|b|大 else if(la==lb) for (int q=la;q>=1;q--) //cout<<a[q]<<" "<<b[q]<<endl; if(a[q]>b[q]) bigger=0; break; else if(a[q]<b[q]) bigger=1; break; if(bigger==0) //a更大 for(int q=1;q<=la;q++) a[q]-=b[q]; if(a[q]<0) a[q]+=10; a[q+1]--; if(a[q]!=0) rec=q; if(rec!=0) cout<<"-"; for(int q=rec;q>=1;q--) cout<<a[q]; else cout<<0; else if(bigger==1) //b更大 for(int q=1;q<=lb;q++) b[q]-=a[q]; if(b[q]<0) b[q]+=10; b[q+1]--; if(b[q]!=0) rec=q; if(rec!=0) for(int q=rec;q>=1;q--) cout<<b[q]; else cout<<0; else if(b1[0]==‘-‘) //a为正,b为负 int rec=0; la=strlen(a1); lb=strlen(b1)-1; for(int i=0;i<=la-1;i++) //进行倒序a a[la-i]=a1[i]-‘0‘; //cout<<la-i<<" "<<a[la-i]<<"||"; //cout<<endl; for (int j=0;j<=lb-1;j++) //进行倒序b b[lb-j]=b1[j+1]-‘0‘; //cout<<lb-j<<" "<<b[lb-j]<<"||"; //cout<<endl; if(la>lb) bigger=0; //|a|大 else if(la<lb) bigger=1; //|b|大 else for (int q=la;q>=1;q--) //cout<<a[q]<<" "<<b[q]<<endl; if(a[q]>b[q]) bigger=0; break; else if(a[q]<b[q]) bigger=1; break; if(bigger==0) //a更大 for(int q=1;q<=la;q++) a[q]-=b[q]; if(a[q]<0) a[q]+=10; a[q+1]--; if(a[q]!=0) rec=q; if(rec!=0) for(int q=rec;q>=1;q--) cout<<a[q]; else cout<<0; else if(bigger==1) //b更大 for(int q=1;q<=lb;q++) b[q]-=a[q]; if(b[q]<0) b[q]+=10; b[q+1]--; if(b[q]!=0) rec=q; if(rec!=0) cout<<"-"; for(int q=rec;q>=1;q--) cout<<b[q]; else cout<<0; return 0;
以上是关于51nod基础题感触(1005大数加法)的主要内容,如果未能解决你的问题,请参考以下文章