当前位置: 首页 > news >正文

2025年7月11日—基础算法—高精度

算法基础

文章目录

  • 0.算法介绍
  • 1.A+B Problem(高精)
    • 1.1 题目速览
    • 1.2.算法设计
    • 1.3.代码实现
  • 2.高精度减法
    • 2.1 题目速览
    • 2.2 算法设计
    • 2.3 代码实现
  • 3.A*B Problem
    • 3.1 题目速览
    • 3.2 算法设计
    • 3.3 代码实现
  • 4. A/B Problem
    • 4.1 题目速览
    • 4.2 算法设计
    • 4.3 代码实现
  • 5.算法模版总结

0.算法介绍

当数据的值特别大,各种类型都存不下的时候,此时就要用高精度算法来计算加减乘除:

  • 先用字符串string读入这个数,然后用数组逆序存储该数的每一位;
  • 利用数组,模拟加减乘除运算的过程。

高精度算法本质上还是模拟算法,用代码模拟小学列竖式计算加减乘除的过程。

1.A+B Problem(高精)

1.1 题目速览

题目链接:P1601 A+B Problem(高精) - 洛谷

image-20250711143450961

1.2.算法设计

这类题我们无法通过直接相加,因为位数过大会造成越界的情况

所以我们只能通过字符串将相加的数存起来,后通过数组直接模拟加法的竖式计算即可如下图:

image-20250711144712781

竖式计算的加法是从末尾向前加的,所以我们需要将字符串反向存到数组中

我们可以通过找对应下标的规律来逆向存放(这也是我们本章高精度的所有题目的基础,后续就默认已经逆向存放好了):

image-20250711145618005

接下来是模拟列竖式计算的过程:

  1. 对应位累加:直接用第三个数组存入

    这里第三个数组的长度我们在加法中可以先确定和最大的那个数的长度保持一致,后续在根据实际结果进行调整

  2. 处理进位:前一位等于当前为/10就是进位–> arr[i+1] = arr[i]/10

  3. 处理余数:当前为%10取余即可

  4. 确定结果位数:后续还需要处理如下图这种,如果从最长的三位数变为四位数的时候,需要判定一下数组的最后一位是否为0,不为0直接将长度加上

image-20250711151759035

1.3.代码实现

#include <iostream>
using namespace std;
#include <string>const int N = 1e6 + 10;
//变量如果定义为全局变量就无需我们等会在向函数传参了
int a[N], b[N], c[N];
int la, lb, lc;
string s1, s2;//高精度加法主要逻辑
void add()
{for (int i = 0; i < lc; i++){c[i] += a[i] + b[i];  //对应位相加c[i + 1] = c[i] / 10; //处理进位c[i] %= 10;           //处理余数}if (c[lc]) lc++;  //处理结果位数,如从三位数变为四位数
}
int main()
{cin >> s1 >> s2;//1.拆分每一位,逆序存放到数组中la = s1.size(), lb = s2.size();lc = max(la, lb);for (int i = 0; i < la; i++) a[i] = s1[la - 1 - i] - '0';for (int i = 0; i < lb; i++) b[i] = s2[lb - 1 - i] - '0';//2.模拟加法过程add();//输出结果for (int i = lc - 1; i >= 0; i--) cout << c[i];return 0;
}

2.高精度减法

2.1 题目速览

题目链接:P2142 高精度减法 - 洛谷

image-20250711143524925

2.2 算法设计

竖式减法模拟过程如下:

image-20250711191355985

由于是减法,所以无法直接相减,需要大数减小数,小数减大数可以转化为:先加一个负号,再算大数减小数

那么字符串的比较大小就需要注意字典序了:

也就是需要先判断长度是否一致,一致了才能直接比较,不一致则长度大的数值大,比较代码如下:

bool cmp(string& s1, string& s2)
{//先比较长度if (s1.size() != s2.size()) return s1.size() < s2.size();//在按照字典序比较return s1 < s2;
}

接着还是要将字符串导致放入到数组中,与前一题的步骤一致

模拟列竖式计算的过程:

  1. 对应位求差:直接相减

    这里第三个数组的长度仍然可以先确定和最大的那个数的长度保持一致,后续在根据实际结果进行调整

  2. 处理借位:对相减为负数的数进行结尾

  3. 确定结果位数:如下图,如果结果前面有0,就需要再写一个循环将前面的0消掉

    image-20250711192336956

2.3 代码实现

#include <iostream>
using namespace std;
#include <string>const int N = 1e6 + 10;
int a[N], b[N], c[N];
int la, lb, lc;
string s1, s2;//比较大小
bool cmp(string& s1, string& s2)
{//先比较长度if (s1.size() != s2.size()) return s1.size() < s2.size();//在按照字典序比较return s1 < s2;
}
//实现高精度减法
void sub()
{for (int i = 0; i < lc; i++){c[i] += a[i] - b[i];  //对应位置相减if (c[i] < 0){c[i + 1]--; //借位c[i] += 10;}}while (lc > 1 && c[lc - 1] == 0) lc--;  //处理前导0
}
int main()
{cin >> s1 >> s2;//比较大小如果需要交换那么结果也就是负数了if (cmp(s1, s2)){swap(s1, s2);cout << '-';}//1.拆分每一位,逆序存放到数组中la = s1.size(), lb = s2.size();lc = max(la, lb); //结果的位数先确定为最大的,后面在处理得到真正的位数for (int i = 0; i < la; i++) a[i] = s1[la - 1 - i] - '0';for (int i = 0; i < lb; i++) b[i] = s2[lb - 1 - i] - '0';//2.模拟减法过程sub();//3.输出结果for (int i = lc - 1; i >= 0; i--) cout << c[i];return 0;
}

3.A*B Problem

3.1 题目速览

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

image-20250711143609586

3.2 算法设计

与前面的不同,想要让我们的代码简单一些,就不能和竖式乘法一样,每次都进行进位了

我们可以相统一进行相加,在统一进行进位操作

乘法是需要两个数字全部进行枚举,且有存放的位置有一定对应关系如下图:

image-20250711192824864

那么不难发现其实就是枚举数组当前位置的下标直接相加即可,这部分代码可写作:

for (int i = 0; i < la; i++)
{for (int j = 0; j < lb; j++){c[i + j] += a[i] * b[j];}
}

接着还是要将字符串导致放入到数组中,与前一题的步骤一致

模拟无进位相乘再相加的过程:

  1. 对应位求乘积:与前面一样直接加到第三个数组中

    这里第三个数组的长度我们在可以预估成相乘最大值(两位数乘两位数,最大为四位数),后续在根据实际结果进行调整

  2. 乘完之后处理进位:与加法处理方式相同

  3. 处理前导0:与减法处理方式相同

3.3 代码实现

#include <iostream>
using namespace std;
#include <string>const int N = 1e6 + 10;
int a[N], b[N], c[N];
int la, lb, lc;
string s1, s2;//模拟高精度乘法
void mul()
{//无进位相乘,在相加for (int i = 0; i < la; i++){for (int j = 0; j < lb; j++){c[i + j] += a[i] * b[j];}}//处理进位for (int i = 0; i < lc; i++){c[i + 1] += c[i] / 10;c[i] %= 10;}//处理前导0while (lc > 1 && c[lc - 1] == 0) lc--;
}
int main()
{cin >> s1 >> s2;la = s1.size(), lb = s2.size();lc = la + lb;//1.拆分每一位,逆序存放到数组中for (int i = 0; i < la; i++) a[i] = s1[la - 1 - i] - '0';for (int i = 0; i < lb; i++) b[i] = s2[lb - 1 - i] - '0';//2.模拟乘法过程mul();//3.输出结果for (int i = lc - 1; i >= 0; i--) cout << c[i];return 0;
}

4. A/B Problem

4.1 题目速览

题目链接:P1480 A/B Problem - 洛谷

image-20250711143634966

4.2 算法设计

这道题需要注意的是:不是真正的高精度/高精度,而是高精度/低精度

image-20250711194022110

我们可以定义一个指针 i 从「高位」遍历被除数,一个变量 t 标记当前「被除的数」,记除数是 b

  • 更新当前被除的数 t = t × 10 + a[i]
  • t/b 表示这一位的商,t%b 表示这一位的余数
  • t 记录这一次的余数,遍历到下一位的时候重复上面的过程

被除数遍历完毕之后,t 里面存的就是余数,但是商可能存在前导 0,注意清空

4.3 代码实现

#include <iostream>
using namespace std;
#include <string>const int N = 1e6 + 10;
int a[N], c[N];
int la, b, lc;
string s1;//模拟高精度除法
void mul()
{long long t = 0;  //标记每次除完之后的余数for (int i = lc - 1; i >= 0; i--){//计算当前的被除数t = t * 10 + a[i];c[i] = t / b;t = t % b;}//处理前导0while (lc > 1 && c[lc - 1] == 0) lc--;
}
int main()
{cin >> s1 >> b;la = s1.size();lc = la;//1.拆分每一位,逆序存放到数组中for (int i = 0; i < la; i++) a[i] = s1[la - 1 - i] - '0';//模拟除法过程mul();for (int i = lc - 1; i >= 0; i--) cout << c[i];return 0;
}

5.算法模版总结

那么我们将这几个题目的核心内容拿出就可以组成高精度算法的模版了,如下:

//高精度加法主要逻辑
void add()
{for (int i = 0; i < lc; i++){c[i] += a[i] + b[i];  //对应位相加c[i + 1] = c[i] / 10; //处理进位c[i] %= 10;           //处理余数}if (c[lc]) lc++;  //处理结果位数,如从三位数变为四位数
}//高精度减法主要逻辑
void sub()
{for (int i = 0; i < lc; i++){c[i] += a[i] - b[i];  //对应位置相减if (c[i] < 0){c[i + 1]--; //借位c[i] += 10;}}while (lc > 1 && c[lc - 1] == 0) lc--;  //处理前导0
}//高精度乘法主要逻辑
void mul()
{//无进位相乘,在相加for (int i = 0; i < la; i++){for (int j = 0; j < lb; j++){c[i + j] += a[i] * b[j];}}//处理进位for (int i = 0; i < lc; i++){c[i + 1] += c[i] / 10;c[i] %= 10;}//处理前导0while (lc > 1 && c[lc - 1] == 0) lc--;
}//高精度除法主要逻辑
void mul()
{long long t = 0;  //标记每次除完之后的余数for (int i = lc - 1; i >= 0; i--){//计算当前的被除数t = t * 10 + a[i];c[i] = t / b;t = t % b;}//处理前导0while (lc > 1 && c[lc - 1] == 0) lc--;
}
http://www.dtcms.com/a/274369.html

相关文章:

  • 删除mysql文件夹时显示在另一程序中打开
  • 期权交易完整版教程简介
  • 工具分享--IP与域名提取工具
  • YOLOv13来了!基于超图增强的自适应视觉感知实时目标检测
  • 数据结构第一章复杂度的认识
  • WebSocket 重连与心跳机制:打造坚如磐石的实时连接
  • 005---Xilinx Viivado FIFO (二)---fifo IP核使用总结
  • python之set详谈
  • 大数据驱动的酒店用品需求预测模型研究 开发——毕业论文,毕业设计——仙盟创梦IDE
  • Linux驱动基本概念(内核态、用户态、模块、加载、卸载、设备注册、字符设备)
  • linux文件系统目录结构以及交互界面
  • 稳定币将成为新时代的重要金融工具
  • Pandas:数据类型转换
  • c99-柔性数组
  • NVME在ubuntu上总是导致死机
  • Android simpleperf生成火焰图
  • 深度解析 DApp 开发:从技术架构到商业落地的全链路解决
  • Linux 进程管理核心机制
  • 掌握Spring声明式事务传播机制:AOP与ThreadLocal的协同工作
  • 破解异构日志清洗五大难题,全面提升运维数据可观测性
  • 用FunctionCall实现文件解析(一):环境准备与基础知识
  • uniapp语音播报天气预报微信小程序
  • 秒杀系统该怎么设计?
  • uniapp-在windows上IOS真机运行(含开发证书申请流程)
  • 在Spring Boot 开发中 Bean 的声明和依赖注入最佳的组合方式是什么?
  • Spring Boot集成Redis:从配置到实战的完整指南
  • Adobe Acrobat DC JavaScript 基础到应用
  • python的卷烟营销数据统计分析系统
  • 重学前端003 --- CSS 颜色
  • 汽车级MCU选型新方向:eVTOL垂桨控制监控芯片的替代选型技术分析