算法题目 - 高精度算法(蓝桥杯)

02_高精度算法

1.高精度加法

1.概念讲解

  • 本质:模拟算法
  • 当数据类型特别大,各种数据类型都无法存放时,此时就需要高精度算法的加减乘除:
    • 什么意思?我们通常所接触到的数据范围一般为109 (int存放) ~ 1018 (long long存放) 级别,当数据的范围达到10100000 (甚至百万次方时),我们所学到的任何数据类型都是无法存放它们的,此时我们就需要用到高精度算法。
  • 使用步骤:
    • 用字符串读入这个数,再用数组逆序存储该数的每一位。
    • 为什么使用字符串存储数字呢?因为在计算机视角看待一串数字(如 123 ),计算机会将其视作:‘1’(字符1), ‘2’, ‘3’。
    • 又为什么使用数组逆序存储?数字在数组中的存储方式其实是逆序的(int arr[ ] = {个位, 十位, 百位, 千位……}) - 从最低位至高位;因此如:123,其每一位在数组中的对应位置,int arr[ ] = {3, 2, 1};),以此方便加法计算的进位处理。
    • 利用数组模拟加减乘除的过程

2.P1601 A+B Problem(高精)

题目来源:洛谷

题目链接:P1601 A+B Problem(高精))(如果无法打开可浏览器搜索洛谷,题库输入:P5731)

题目难度:*

题目描述

高精度加法,相当于 a+b problem,不用考虑负数

输入格式

分两行输入。 a , b ≤ 1 0 500 a,b \leq 10^{500} a,b10500

输出格式

输出只有一行,代表 a + b a+b a+b 的值。

输入输出样例 #1
输入 #1
1
1
输出 #1
2
输入输出样例 #2
输入 #2
1001
9099
输出 #2
10100
说明/提示

20 % 20\% 20% 的测试数据, 0 ≤ a , b ≤ 1 0 9 0\le a,b \le10^9 0a,b109

40 % 40\% 40% 的测试数据, 0 ≤ a , b ≤ 1 0 18 0\le a,b \le10^{18} 0a,b1018

3.代码思路

​ **a.**拆分每一位,将其逆序放入数组中

//我们定义一个字符串439,并将其存放在数组中
string s = "4  3  9";
idex        0  1  2
            ^
            i(假设指针 i 从前向后遍历时指向1) 
    
//显而易见,数字字符串在数组中是以逆序的形式存储的
int a[] = {
     
     '9', '3', '4'};
idex        0    1    2
//两下标和   2    2     2
                      ^
                      j
//可得出下标对应关系:j = s.size() - 1 - i
//即可得出结论:元素s[i] 对应存放 在数组 a 中的位置为 j,因此 a[j] == s[i];

**b.**模拟计算加法过程,并考虑进位情况

  • 对应位相加,再加上进位
  • 处理进位:x / 10
  • 处理余数:x % 10
//模拟 数组 c 存储 a + b 后的结果
1.
int a[] = {
     
     2, 4, 7, 0, 0, 0};
int b[] = {
     
     4, 9, 2, 1, 0, 0};
           ^
int c[] = {
     
     6, (6 / 10) == 0,因此进位为0}

2.
int a[] = {
     
     2, 4, 7, 0, 0, 0};
int b[] = {
     
     4, 9, 2, 1, 0, 0};
              ^
int c[] = {
     
     6, 0(进位) + 13(对应位相加), (13 / 10) == 1,因此进位1}3.
int a[] = {
     
     2, 4, 7, 0, 0, 0};
int b[] = {
     
     4, 9, 2, 1, 0, 0};
                 ^
int c[] = {
     
     6, 3,  1 + 9(10 / 10 == 1,因此进位1)}4.               
int a[] = {
     
     2, 4, 7, 0, 0, 0};
int b[] = {
     
     4, 9, 2, 1, 0, 0};
                    ^
int c[] = {
     
     6, 3,  01 + 0 + 1}//最终
int c[] = {
     
     6, 3, 0, 2};//2036

4.代码实现

#include<iostream>
using namespace std;
#include <algorithm>

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

int la, lb, lc;//标记对应数组中的长度 

//高精度加法的模板 - c = a + b; 
void add(int c[], int a[], int b[])
{
    
    
	//将最终的计算结果放入 c 中
	for(int i = 0; i < lc; i++)
	{
    
    
		c[i] += a[i] + b[i];//注意事项:"+=",因为 c[i] 这个位置可能存在进位,
		//所以在进行对位相加时需要把进位加入 c[i] 中 (对位相加,再加上进位) 
		
		c[i + 1] += c[i] / 10;//处理进位
		c[i] %= 10;//处理余数
	} 
	
	//处理边界问题,如果 lc 指向位置存在值(说明上步计算结果出现了进位),因此需要实际长度(lc) + 1
	if(c[lc]) lc++; 
} 

int main()
{
    
    
	//每个数使用字符串的方式读入
	string x, y;cin >> x >> y;
	
	//1.拆分每一位,并逆序放入数组中
	la = x.size();lb = y.size(); lc = max(la, lb);
	for(int i = 0; i < la; i++) a[la - 1 - i] = x[i] - '0';//因为 x[i] 中存放的其实是字符,需要 - '0' 变为 int
	for(int i = 0; i < lb; i++) b[lb - 1 - i] = y[i] - '0';// i 位置的字符(元素),在数组中所对应的位置:长度 - 1 - i 
	
	//2.模拟加法的过程
	add(c, a, b);// c = a + b;
	
	//输出结果
	for(int i = lc - 1; i >= 0; i--)//因为数字存放在数组的方式是逆序的,因此需要逆向输出 
	//eg: 123
	//数组存储方式:int arr[] = {'3', '2', '1'}; - 以字符类型且 逆序 的方式来存储 字符串123 
	{
    
    
		cout << c[i];
	} 
	return 0;
}