P1303 A*B Problem 题解
题目传送门:P1303 A*B Problem
一、题目描述
给定两个非负整数(可能非常大,长度不超过2000位),要求计算它们的乘积并输出结果。
二、题目分析
这道题是一个典型的高精度乘法问题。由于输入的数字可能非常大(达到10^2000),远远超过任何基本数据类型的表示范围,因此不能直接用常规的乘法运算,需要实现高精度算法来逐位计算。
三、解题思路 + 算法讲解
解题思路采用模拟手工乘法的方法:
- 数字存储:将输入的大数字符串逆序存储到数组中(个位在前),方便从低位开始计算
- 逐位相乘:使用双重循环,将第一个数的每一位与第二个数的每一位相乘
- 处理进位:将每一位的乘积累加到结果数组的对应位置,然后统一处理进位
- 去除前导零:确保结果的最前面没有多余的零
- 输出结果:将结果数组逆序输出(高位在前)
- 图片描述
这种方法模拟了我们在纸上做乘法时的竖式计算过程,但通过数组存储和循环处理,可以应对任意长度的数字。
四、代码实现
#include <iostream>
#include <vector>
using namespace std;
// 定义两个字符串 a 和 b,用于存储输入的两个大整数
string a, b;
// 定义两个向量 A 和 B,用于将输入的字符串按位存储为整数,方便后续计算
vector<int> A, B;
// 定义一个函数 mul,用于实现两个大整数的乘法,参数为两个整数向量的引用
vector<int> mul(vector<int> &A, vector<int> &B)
{
// 初始化结果向量 C,其大小设置为 A 的大小加上 B 的大小再加上 10,确保有足够的空间存储结果
// 初始值都设为 0
vector<int> C(A.size() + B.size() + 10, 0);
// 双重循环遍历 A 和 B 的每一位
for (int i = 0; i < A.size(); i++)
for (int j = 0; j < B.size(); j++)
{
// 将 A 的第 i 位和 B 的第 j 位相乘,结果累加到 C 的第 i + j 位上
// 这里使用 += 是因为可能会有多次累加
C[i + j] += A[i] * B[j];
}
// 用于处理进位的变量
int t = 0;
// 遍历结果向量 C 的每一位
for (int i = 0; i < C.size(); i++)
{
// 将当前位的值加上进位 t
t += C[i];
// 当前位只保留个位数字
C[i] = t % 10;
// 计算进位,将 t 除以 10
t /= 10;
}
// 去除结果向量 C 末尾的前导 0,但要保证结果至少有一位
while (C.size() > 1 && C.back() == 0)
C.pop_back();
// 返回处理后的结果向量 C
return C;
}
int main()
{
// 从标准输入读取两个大整数,存储到字符串 a 和 b 中
cin >> a >> b;
// 将字符串 a 按位倒序存储到向量 A 中,方便从低位开始计算
for (int i = a.size() - 1; i >= 0; i--)
{
// 将字符转换为对应的整数并添加到向量 A 中
A.push_back(a[i] - '0');
}
// 将字符串 b 按位倒序存储到向量 B 中,方便从低位开始计算
for (int i = b.size() - 1; i >= 0; i--)
{
// 将字符转换为对应的整数并添加到向量 B 中
B.push_back(b[i] - '0');
}
// 调用 mul 函数计算 A 和 B 的乘积,结果存储在向量 C 中
auto C = mul(A, B);
// 从高位到低位输出结果向量 C 的每一位
for (int i = C.size() - 1; i >= 0; i--)
printf("%d", C[i]);
return 0;
}
五、重点细节
- 逆序存储:将输入的数字字符串逆序存储,这样个位在数组开头,方便从低位开始计算
- 结果数组初始化:结果数组大小设置为A.size()+B.size()+10,确保有足够空间存储所有可能的位数
- 进位处理:在逐位相乘后,需要统一处理进位,而不是每次相乘都处理,这样更高效
- 前导零处理:最后需要去除结果中可能存在的多余前导零,但要保留至少一位(即使是0)
- 输出顺序:由于存储是逆序的,输出时需要从后往前输出
六、复杂度分析
- 时间复杂度:O(n*m),其中n和m分别是两个输入数字的长度。因为有两重循环分别遍历两个数字的每一位
- 空间复杂度:O(n+m),用于存储输入数字和结果
七、总结
这道高精度乘法题目考察了对大数处理的能力,通过模拟手工乘法的方式,我们可以有效地解决这个问题。关键在于:
- 合理地存储大数(逆序存储方便计算)
- 正确处理每一位的乘积和进位
- 注意边界情况(如乘数为0的情况)
掌握这种高精度计算方法对于处理大数运算问题非常重要,是算法竞赛中的基础技能之一。