高精度算法题就是指简单的加减乘除题,但是加减的数据极大,无法用int、long long等数据类型表示,因此可以通过字符数组来表示,再转换为整形数组运算。(该类题型一般作为基础运用于较难的运算题目中)
一、高精度算法题之加(减):
例题:(减也大差不差)
A + B Problem II
时间限制(普通/Java):1000MS/10000MS 内存限制:65536KByte
描述
I have a very simple problem for you. Given two integers A and B, your job is to calculate the Sum of A + B.
输入
The first line of the input contains an integer T(1<=T<=20) which means the number of test cases. Then T lines follow, each line consists of two positive integers, A and B. Notice that the integers are very large, that means you should not process them by using 32-bit integer. You may assume the length of each integer will not exceed 1000.
输出
For each test case, you should output two lines. The first line is "Case #:", # means the number of the test case. The second line is the an equation "A + B = Sum", Sum means the result of A + B. Note there are some spaces int the equation. Output a blank line between two test cases.
样例输入
2
1 2
112233445566778899 998877665544332211
样例输出
Case 1:
1 + 2 = 3
Case 2:
112233445566778899 + 998877665544332211 = 1111111111111111110
题目注意点:
1.注意数组的初始化,不对数组再次归零会出错;
2.字符数组转整形数组容易出错;
3.注意入录数组后的数字顺序,在计算时容易出现错误;
4.注意的范围与顺序;
AC代码:
#include<bits/stdc++.h>
using namespace std;
char xc[1005]={0},yc[1005]={0};
int x[1005]={0},y[1005]={0},z[1005]={0}; // 定义字符数组xc和yc来存储输入的整数,整数数组x、y和z来存储转换后的整数
int l; //用于存储数组长度
// 定义函数Add,用于执行大整数加法。函数内部使用循环来处理每一位的加法,并处理可能的进位
void Add(){
for(int j=0;j<l;j++){
z[j]+=x[j]+y[j];
z[j+1]+=z[j]/10; // 计算进位,并存储在z[j+1]中
z[j]=z[j]%10; // 计算z[j]的个位数,并存储在z[j]中
//运行错误时,可以在以下的printf来判断自己的错误点 (这也是wrong时修改题目的技巧)
//printf("j=%d x[j]=%d y[j]=%d z[j]=%d z[j+1]=%d\n",j,x[j],y[j],z[j],z[j+1]);
}
if(z[l]>0) l++; // 如果z[l]大于0,说明还有进位,需要额外处理
return;
}
int main(){
int t,lx,ly;
scanf("%d",&t);
for(int i=1;i<=t;i++){
scanf("%s%s",&xc,&yc);
lx=strlen(xc);
ly=strlen(yc);
l=max(lx,ly); // 对于每个测试用例,读取两个整数,并计算它们的长度,然后获取长度较大的那个作为l
for(int j=0;j<lx;j++)
x[lx-j-1]=xc[j]-'0';
for(int j=0;j<ly;j++)
y[ly-j-1]=yc[j]-'0';
// 将字符数组转换为整数数组
Add();
// 调用Add函数执行加法
printf("Case %d:\n",i);
printf("%s + %s = ",xc,yc);
for(int j=l-1;j>=0;j--){
printf("%d",z[j]);
// 每次输出后,将x[j]、y[j]和z[j]清零,以便下一次测试用例使用
x[j]=y[j]=z[j]=0;
}
// 输出结果,并在每个测试用例之间输出一个空行
if(i!=t) printf("\n\n");
}
return 0;
}
二、高精度算法题之乘:
高精度乘法
时间限制(普通/Java):1000MS/3000MS 内存限制:65536KByte
描述
输入两个高精度非负整数M和N(M和N均小于100位)。求这两个高精度数的积。
输入
输入两个高精度非负整数M和N。
输出
求这两个高精度数的积,结果不含前导0。
样例输入
36
3
样例输出
108
题目注意点:
1.注意结果的储存数组要大,不同于加减;
2.乘除运算方法与加减的巨大不同;
3.结果数组的长度为俩乘数数组的相加,并不断减小;(例如两个二位数相乘可以为四位数也可以为三位数)
提示:
AC代码:
#include<bits/stdc++.h>
using namespace std;
char xc[105]={0},yc[105]={0};
int x[105]={0},y[105]={0},z[100005]={0};
int l,lx,ly;
// 定义字符数组xc和yc来存储输入的整数,整数数组x、y和z来存储转换后的整数,以及整数l来存储数组长度
void Multiply(){
for(int j=0;j<lx;j++){ // 遍历x数组的每一位
for(int k=0;k<ly;k++){ // 遍历y数组的每一位
z[j+k]+=x[j]*y[k];
z[j+k+1]+=z[j+k]/10;
z[j+k]%=10;
}
}
while(l&&z[l]==0) l--; // 存余,且存在乘数为0的可能,所以要加l
return;
}
// 定义函数Multiply,用于执行高精度乘法。函数内部使用两层循环来处理每一位的乘法,并处理可能的进位
int main(){
scanf("%s%s",&xc,&yc);
lx=strlen(xc);
ly=strlen(yc);
l=lx+ly;
for(int j=0;j<lx;j++)
x[lx-j-1]=xc[j]-'0';
for(int j=0;j<ly;j++)
y[ly-j-1]=yc[j]-'0';
Multiply();
for(int j=l;j>=0;j--){
printf("%d",z[j]);
x[j]=y[j]=z[j]=0;
}
return 0;
}
三、高精度算法题之除:
高精除
时间限制(普通/Java):1000MS/3000MS 内存限制:65536KByte
描述
高精除以高精,求它们的商和余数。
输入
输入两个低于300位的正整数。
输出
输出商和余数。
样例输入
1231312318457577687897987642324567864324567876543245671425346756786867867867
1231312318767141738178325678412414124141425346756786867867867
样例输出
999999999748590
179780909068307566598992807564736854549985603543237528310337
题目提示:
1.主要要注意运算的是第几位;
2.关键点较多,看代码和解析吧;(代码写的好累,下次有空再补注意点吧)
AC代码:
#include<bits/stdc++.h>
using namespace std;
const int N=305; // 定义常量N为305,用于数组的长度
char xc[N]={0},yc[N]={0}; // 定义字符数组xc和yc,用于存储输入的整数,初始化为0
int x[N]={0},y[N]={0},z[N]={0},q[N]={0}; // 定义整数数组x、y、z和q,用于存储转换后的整数
int l,lx,ly; // 定义整数l、lx和ly,用于存储数组长度
// 函数Can用于判断是否可以减去除数
bool Can(int j){
if(x[j+ly]>0){ // 如果被除数的下一位大于0,返回true
return true;
}
for(int i=ly-1;i>=0;i--){ // 从除数的最高位开始,逐位比较
if(x[j+i]<y[i]) return false; // 如果被除数小于除数,返回false
else if(x[j+i]>y[i]) return true; // 如果被除数大于除数,返回true
}
return true; // 如果相等,返回true
}
// 函数Multiply用于执行除法操作
void Multiply(){
for(int i=l-1;i>=0;i--){ // 从被除数的最高位开始,逐位进行除法操作
while(Can(i)){ // 如果可以减去除数
z[i]++; // 商加1
for(int j=0;j<ly;j++){ // 逐位执行减法操作
if(x[i+j]>=y[j]) x[i+j]-=y[j]; // 如果被除数大于等于除数,直接相减
else{ // 如果被除数小于除数,需要借位
x[i+j+1]--; // 高位减1
x[i+j]+=10-y[j]; // 当前位加10再减去除数的对应位
}
}
}
}
return ;
}
int main(){
scanf("%s%s",&xc,&yc); // 输入两个整数,作为字符串
lx=strlen(xc); // 计算第一个整数的长度
ly=strlen(yc); // 计算第二个整数的长度
l=lx-ly+1; // 计算商的长度
for(int j=0;j<lx;j++) x[lx-j-1]=xc[j]-'0'; // 将第一个整数转换为整数数组
for(int j=0;j<ly;j++) y[ly-j-1]=yc[j]-'0'; // 将第二个整数转换为整数数组
Multiply(); // 调用Multiply函数执行除法操作
int f=1; // 定义变量f,用于判断是否有前导零
for(int j=lx-1;j>=0;j--){ // 输出商
if(!f||z[j]>0){ // 如果不是前导零或者当前位大于0
printf("%d",z[j]); // 输出当前位
z[j]=0; // 将当前位清零
f=0; // 标记为没有前导零
}
}
if(f) printf("0"); // 如果所有位都是前导零,输出0
printf("\n"); // 输出换行符
f=1; // 重置变量f,用于判断余数的前导零
for(int j=lx-1;j>=0;j--){ // 输出余数
if(!f||x[j]>0){ // 如果不是前导零或者当前位大于0
printf("%d",x[j]); // 输出当前位
x[j]=0; // 将当前位清零
f=0; // 标记为没有前导零
}
}
if(f) printf("0"); // 如果所有位都是前导零,输出0
return 0;
}
结束语:
作为一个萌新,想着记录一下学习的一点点进度,并且给大家分享一下我的想法。作为第一篇博客,希望读者大大能给点改良的建议哦,Thanks♪(・ω・)ノ
也希望能为你们提供到一些帮助,如果有帮助的话,给个免费的三连吧,
爱你(๑′ᴗ‵๑)I Lᵒᵛᵉᵧₒᵤ❤