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大数加法)的主要内容,如果未能解决你的问题,请参考以下文章

51nod 1005 大数加法

51Nod1005 大数加法

51nod 1005 大数加法

1005 大数加法

大数加法 51nod 转载自 逐梦者

大数加法 模板