一、前言
我是夏日弥,很高兴看到您来读我的博客,
这一次小夏将为您讲解一道经典的算法竞赛入门题,使用的方法涉及高精度加法和减法,vector动态数组,这是一种比较容易想得到,却不好代码实现的方法。
于此同时,我会为您提供另一种代码比较简洁,却不是很好理解的方法——消零法;
时间有限,本次讲解会比较简洁,还请您包容和理解,让我们正式开始吧!
二、大数之和
2.1、题目:大数之和:
给定一些大整数,请计算其和。
输入格式:
测试数据有多组。对于每组测试数,首先输入一个整数n(n≤100),接着输入n个大整数(位数不超过200)。若n=0则表示输入结束。
输出格式:
对于每组测试,输出n个整数之和,每个结果单独占一行。
输入样例:
2
43242342342342
-1234567654321
0
输出样例:
42007774688021
2.2、高精度加减法模拟:
#include
using namespace std;
const int N =100010;
vector add(vector& A,vector& B)
{
vector C;
int t = 0;
for(int i =0;i &A,vector &B)
{ cout<<"cmp函数已执行"<= 0;i--)cout<= 0;i--)cout< B.size();//长度不一样时可以直接判断,返回A.size() > B.size()的真假;
for(int i = A.size()-1; i >= 0;i--) //末尾往前依次判断;
if(A[i] != B[i])return A[i] > B [i];//例如987和986比较,从末尾7和6比,直接返回7>6为真,即a>b为真;
return true; //如果两数相等,返回为真;
}
vector sub(vector &A,vector &B)//该函数必须确保A>=B;
{
vector C;//定义答案数组C;
for(int i = 0,t = 0; i0,说明没有借位;
}
while(C.size() > 1 && C.back() == 0)C.pop_back();//头部消零,C.size()>1 确保了C里面不是一位数,如果 C 是0的话是不用消去的;
return C;
}//高精度减法函数,返回值为vector数组类型;
vector trans(string a){
vector C;
for(int i=a.size()-1;i>=0;i--)C.push_back(a[i]-'0');
return C;
}
int main(){
int n;
while(cin>>n && n!=0 ){
vector ans={0};//每一次都定义新的ans;
bool ans_bool = 1;//新的ans_bool的状态为 正;
bool a_bool = 1;//新的a_bool的状态为 正;
for(int j = 0; j>a;//输入部分;
vector A ;
if(a[0] == '-'){
a_bool = 0;//如果是负数,更新a_bool为负数;
for(int i = a.size()-1;i>0;i--)A.push_back(a[i]-'0');
}
else{
a_bool = 1;//如果是正数,更新a_bool为正数;
A = trans(a);//取a的绝对值;
}
//取值部分&判断部分;
cout<<"这里将输出ans_bool 和a_bool 的值,分别是 "ans;
//比较部分:ans和A到底谁大?
}
cout<=0;i--)cout<=0;i--)cout<
420077746880212.2、高精度加减法模拟:
#includeusing namespace std; const int N =100010; vector add(vector & A,vector & B) { vector C; int t = 0; for(int i =0;i &A,vector &B) { cout<<"cmp函数已执行"< = 0;i--)cout<= 0;i--)cout< B.size();//长度不一样时可以直接判断,返回A.size() > B.size()的真假; for(int i = A.size()-1; i >= 0;i--) //末尾往前依次判断; if(A[i] != B[i])return A[i] > B [i];//例如987和986比较,从末尾7和6比,直接返回7>6为真,即a>b为真; return true; //如果两数相等,返回为真; } vector sub(vector &A,vector &B)//该函数必须确保A>=B; { vector C;//定义答案数组C; for(int i = 0,t = 0; i0,说明没有借位; } while(C.size() > 1 && C.back() == 0)C.pop_back();//头部消零,C.size()>1 确保了C里面不是一位数,如果 C 是0的话是不用消去的; return C; }//高精度减法函数,返回值为vector 数组类型; vector trans(string a){ vector C; for(int i=a.size()-1;i>=0;i--)C.push_back(a[i]-'0'); return C; } int main(){ int n; while(cin>>n && n!=0 ){ vector ans={0};//每一次都定义新的ans; bool ans_bool = 1;//新的ans_bool的状态为 正; bool a_bool = 1;//新的a_bool的状态为 正; for(int j = 0; j >a;//输入部分; vector A ; if(a[0] == '-'){ a_bool = 0;//如果是负数,更新a_bool为负数; for(int i = a.size()-1;i>0;i--)A.push_back(a[i]-'0'); } else{ a_bool = 1;//如果是正数,更新a_bool为正数; A = trans(a);//取a的绝对值; } //取值部分&判断部分; cout<<"这里将输出ans_bool 和a_bool 的值,分别是 "ans; //比较部分:ans和A到底谁大? } cout< =0;i--)cout<=0;i--)cout<
我们拆成几个小问题来逐一破解:
1,实现高精度加法模板:
vectoradd(vector & A,vector & B) { vector C;//定义答案数组; int t = 0;//定义临时变量t,储存位数的加法结果,如123+29中的3 + 9 = 12;t = 12; for(int i =0;i 10,t/=10, t = 1; } if(t)C.push_back(1);//特判:如果t = 1,也就是最高位进位,直接压入C的最后一位,如999 + 1 = 000,此时t = 1,压入1使其变为 1000; return C; }//高精度加法;
2、实现高精度减法模板:
bool cmp(vector&A,vector &B) { cout<<"cmp函数已执行"< = 0;i--)cout<= 0;i--)cout< B.size();//长度不一样时可以直接判断,返回A.size() > B.size()的真假; for(int i = A.size()-1; i >= 0;i--) //末尾往前依次判断; if(A[i] != B[i])return A[i] > B [i];//例如987和986比较,从末尾7和6比,直接返回7>6为真,即a>b为真; return true; //如果两数相等,返回为真; } vector sub(vector &A,vector &B)//该函数必须确保A>=B; { vector C;//定义答案数组C; for(int i = 0,t = 0; i0,说明没有借位; } while(C.size() > 1 && C.back() == 0)C.pop_back();//头部消零,C.size()>1 确保了C里面不是一位数,如果 C 是0的话是不用消去的; return C; }//高精度减法函数,返回值为vector 数组类型;
高精度减法比较复杂,因为要判定负数的情况,
我们写的这个模板仅仅限于A >= B 的情况;
负数其实应该是一个...在输入输出被考虑的部分:
我们的加减法本质是 先根据加数的正负计算它们绝对值的和或差
再判断 结果的正负
比如说我们计算 1 - 99 = ?
我们实际上把它变成了 99 - 1 = 98;
再判定 1 为正数, -99 为负数 ,1 的绝对值比 99的绝对值要大,所以取负号;
变成 -98;
3、将string转变成vector
vectortrans(string a){ vector C; for(int i=a.size()-1;i>=0;i--)C.push_back(a[i]-'0'); return C; }
倒序转换,没什么可说的,值得注意的就是 a[i] 是 char型,这里我们采取
a[i] - '0' 的方式转变成 int 类型 如: '9' - '0' = 9;
4、处理输入输出部分:
#includeusing namespace std; int main(){ int n; while(cin>>n && n!=0){ }//多组输入,直到输入0结束; }
最轻松的部分
5、正负号 以及 绝对值大小判定:
小夏的做法是先判定绝对值大小,再判定正负号:
int main(){
int n;
while(cin>>n && n!=0 ){
vector ans={0};//每一次都定义新的ans;
bool ans_bool = 1;//新的ans_bool的状态为 正;
bool a_bool = 1;//新的a_bool的状态为 正;
for(int j = 0; j>a;//输入部分;
vector A ;
if(a[0] == '-'){
a_bool = 0;//如果是负数,更新a_bool为负数;
for(int i = a.size()-1;i>0;i--)A.push_back(a[i]-'0');
}
else{
a_bool = 1;//如果是正数,更新a_bool为正数;
A = trans(a);//取a的绝对值;
}
//取值部分&判断部分;
cout<<"这里将输出ans_bool 和a_bool 的值,分别是 "ans;
//比较部分:ans和A到底谁大?
}
cout<=0;i--)cout<=0;i--)cout<
小夏为您注释了所有的8种情况;
小夏使用的是 ans_bool 和 a_bool 来分别判断 ans 和 a 的正负:1 为正 , 0 为负;
6、连接所有模板
缝合怪,启动!
连接上面的所有模板,再删除注释,最终的程序如下:
最终代码#includeusing namespace std; const int N =100010; vector add(vector & A,vector & B) { vector C; int t = 0; for(int i =0;i &A,vector &B) { if(A.size() != B.size()) return A.size() > B.size();//长度不一样时可以直接判断,返回A.size() > B.size()的真假; for(int i = A.size()-1; i >= 0;i--) //末尾往前依次判断; if(A[i] != B[i])return A[i] > B [i];//例如987和986比较,从末尾7和6比,直接返回7>6为真,即a>b为真; return true; //如果两数相等,返回为真; } vector sub(vector &A,vector &B)//该函数必须确保A>=B; { vector C;//定义答案数组C; for(int i = 0,t = 0; i0,说明没有借位; } while(C.size() > 1 && C.back() == 0)C.pop_back();//头部消零,C.size()>1 确保了C里面不是一位数,如果 C 是0的话是不用消去的; return C; }//高精度减法函数,返回值为vector 数组类型; vector trans(string a){ vector C; for(int i=a.size()-1;i>=0;i--)C.push_back(a[i]-'0'); return C; } int main(){ int n; while(cin>>n && n!=0 ){ vector ans={0};//每一次都定义新的ans; bool ans_bool = 1;//新的ans_bool的状态为 正; bool a_bool = 1;//新的a_bool的状态为 正; for(int j = 0; j >a;//输入部分; vector A ; if(a[0] == '-'){ a_bool = 0;//如果是负数,更新a_bool为负数; for(int i = a.size()-1;i>0;i--)A.push_back(a[i]-'0'); } else{ a_bool = 1;//如果是正数,更新a_bool为正数; A = trans(a);//取a的绝对值; } //取值部分&判断部分; if(cmp(ans,A)){ if(ans_bool && !a_bool){ ans = sub(ans,A); ans_bool = 1; } else if(ans_bool && a_bool){ ans = add(ans , A); ans_bool = 1; } else if(!ans_bool && a_bool){ ans = sub(ans,A); ans_bool = 0; } else if(!ans_bool && !a_bool){ ans = add(ans,A); ans_bool = 0; } }//这个部分是ans>A else{ if(ans_bool && !a_bool){ ans = sub(A,ans); ans_bool = 0; } else if(ans_bool && a_bool){ ans = add(ans , A); ans_bool = 1; } else if(!ans_bool && a_bool){ ans = sub(A,ans); ans_bool = 1; } else if(!ans_bool && !a_bool){ ans = add(ans,A); ans_bool = 0; } }//这个部分是A>ans; //比较部分:ans和A到底谁大? } if(ans_bool){ for(int i = ans.size()-1;i>=0;i--)cout<=0;i--)cout<
2.3、消零法
先加减再消去前导零:
直接放上成果吧:
值得注意的是部分编译器会提示数组越界,但小夏没查过是哪一部分越了界,懒狗
#includeusing namespace std; string sum(string a,string b) { for(int i=201;i>=0;i--) { a[i]=a[i]+b[i]-'0'; if(a[i]>'9'){ a[i]-=10; a[i-1]++; } } return a; } string opp(string a){ for(unsigned int i=0;i>n&&n!=0) { cin>>a; if(a[0]=='-') { a=a.substr(1); a=string(202-a.length(),'0')+a; a=opp(a); } else a=string(202-a.length(),'0')+a; for(int i=0;i >b; if(b[0]=='-') { b=b.substr(1); b=string(202-b.length(),'0')+b; b=opp(b); } else b=string(202-b.length(),'0')+b; a=sum(a,b); } if(a[0]=='9') { a=opp(a); cout<<"-"; } int p=a.find_first_not_of('0'); if(p==-1) cout<<"0"< 三、尾声
草草写的题解;
还请您多加包涵;
夏日弥死傲娇
2021.12.2



