题目链接:P1303 A*B Problem - 洛谷

1.题目分析

2.算法原理

解法:模拟列竖式的过程

  1. 先用字符串读入,然后拆分每一位,逆序放在数组中
  2. 利用数组,模拟列竖式乘法的过程        

3×6=18,要处理18的进位和余数,2×6=12,又加上刚刚进位的1=13,继续处理13的进位和余数,这样的模拟过程很麻烦,给大家介绍一种更加方便的乘法,无进位相乘,然后相加,最后处理进位,就是乘的时候先不处理进位,乘完之后相加,最后再处理进位

无进位相乘相加完后开始处理进位,就是从后往前依次把该进位的数往前进就可以了,比如最后这里的个位18,最后会落上一个八,向前进一个位,余下来,十位27+1=28 ,余8往前进一个2,百位28+2=30,往前进一个3余0,13+3=6,进一位余6,4+1=5,这种处理完的结果就是56088,跟刚刚的计算结果是一样的,且这种模拟方式在中间计算的过程中是不需要频繁的处理进位的,直接把它们相乘,然后相加最后再倒数第二步处理进位是极大的简化了我们的过程的,所以一会我们摸拟的时候就用这种无进位相乘的形式模拟高精度乘法

落实到代码的重点是处理下标,可以发现第二个数的下标0和第一个数的下标012相乘会放到012下标,第二个数的下标1和第一个数的下标012相乘会放在第一个数的下标123,第二个数的下标2和第一个数的下标012相乘会放在下标234的位置,正好是对应的数相加,所以一会我们用两层for循环就搞定了,第一层for循环枚举第二个数里面的每一位,第二层for循环枚举第一个数里面的每一位,假设两层for循环的变量分别是 i j ,结果直接放到c数组里面 i + j 的位置就可以了,让它加等上a[i] * b[j] 就实现了无进位相乘以及相加,循环结束之后再处理进位就可以了

前导0问题

123*0,最终的结果是000,lc下标3走到下标1的时候,lc-1的位置还是0,就不能再减了,因为你最低限度这里面是要存一个0的,所以lc- -的时候要判断一下,lc大于1的时候再去- -,因为lc如果等于1的话,这里即使只剩一个0,lc也不能再减了

代码:

#include <iostream>
using namespace std;

const int N = 1e6 + 10;
int a[N], b[N], c[N];
int la, lb, lc;

// 高精度乘法的模版 - c = a * b
void mul(int c[], int a[], int b[])
{
    // 无进位相乘,然后相加
    for (int i = 0; i < la; i++)
    {
        for (int j = 0; j < lb; j++)
        {
            c[i + j] += a[i] * b[j];
        }
    }

    // 处理进位
    //当前位除10的结果放在前面,模10的结果放在这一位
    for (int i = 0; i < lc; i++)
    {
        c[i + 1] += c[i] / 10;
        c[i] %= 10;
    }

    // 处理前导零
    while (lc > 1 && c[lc - 1] == 0) lc--;
}

int main()
{
    string x, y; cin >> x >> y;

    // 1. 拆分每一位,逆序放在数组中
    la = x.size(); lb = y.size(); lc = la + lb; //过长会在mul函数里处理
    for (int i = 0; i < la; i++) a[la - 1 - i] = x[i] - '0';
    for (int i = 0; i < lb; i++) b[lb - 1 - i] = y[i] - '0';

    // 2. 模拟乘法的过程
    mul(c, a, b); // c = a * b

    // 输出结果
    for (int i = lc - 1; i >= 0; i--) cout << c[i];

    return 0;
}
Logo

集算法之大成!助力oier实现梦想!

更多推荐