高精度整数(n进制,n<=10)加法

来源:互联网 发布:为什么淘宝突然打不开 编辑:程序博客网 时间:2024/04/30 06:21

一、概述

高精度整数的意思即是数据范围极大,已经无法用unsigned long long存储的数据的运算。很多OJ中都有相关练习题(如a+b升级版等),而对于故意给出极大数据的题目此算法为常用算法。
本章仅研究对于10进制以内(2进制~10进制)数的加法。本章将使用例题的讲解方法。

二、例题

例题1

已知两个10进制数a,b,求a+b的值。

数据范围

对于a,b,50%的数据不大于10100

输入输出

输入1

201647458466448 116476489143158

输出1

318123947609606

分析

对于这个数据范围,很明显要使用高精度运算方法。
高精度加法的流程如下。以本题示例为例。
(1)使用char[]存储两个大整数,并将其全部存入int[];
(2)用一个新的int[]存储做完加法的数,按位全部加起来;
(3)处理进位。
流程如下图所示。
示例

实现

#include <cstdio>#include <cstring>char a1[105], b1[105];int a[105], b[105], c[105];int main(void) {    FILE *f = fopen("in.txt", "r");    memset(a, 0, sizeof(a));    memset(b, 0, sizeof(b));    memset(c, 0, sizeof(c));    fscanf(f, "%s%s", a1, b1);    fclose(f);    int alen = strlen(a1), blen = strlen(b1);    int i;    // 倒序放入数字     for(i = 0; i < alen; i++) a[alen - i] = a1[i] - '0';     for(i = 0; i < blen; i++) b[blen - i] = b1[i] - '0';    int clen, decade = 0;    for(clen = 1; clen <= alen || clen <= blen; clen++) {        c[clen] = a[clen] + b[clen] + decade;        decade = c[clen] / 10; // 存储本位的进位         c[clen] %= 10; // 删去本位进位     }    c[clen] = decade; // 处理最高位的进位    if(c[clen] == 0) clen--; // 修正进位后大整数的位数    // 进行完上述过程后,c数组中从0至clen的元素已经存储了各位数字,只需将它们反向输出    for(i = clen; i >= 1; i--) {        printf("%d", c[i]);    }     return 0;}// 注:上面关于一些关键角标的+1或-1操作是为了跳过char[]标志结束的\0 

例题2

已知两个n进制数a,b,求a+b(n进制)的值。

数据范围

对于a,b,50%的数据不大于10100

输入输出

输入1

10
201647458466448 116476489143158

输出1

318123947609606

输入2

2
11111111101010100011 11010001101000101011

输出2

111010001010011001110

分析

更改例题1实现中进位处理即可。

实现

#include <cstdio>#include <cstring>char a1[105], b1[105];int a[105], b[105], c[105];int main(void) {    FILE *f = fopen("in.txt", "r");    memset(a, 0, sizeof(a));    memset(b, 0, sizeof(b));    memset(c, 0, sizeof(c));    int n;    fscanf(f, "%d%s%s", &n, a1, b1);    fclose(f);    int alen = strlen(a1), blen = strlen(b1);    int i;    for(i = 0; i < alen; i++) a[alen - i] = a1[i] - '0';     for(i = 0; i < blen; i++) b[blen - i] = b1[i] - '0';    int clen, decade = 0;    for(clen = 1; clen <= alen || clen <= blen; clen++) {        c[clen] = a[clen] + b[clen] + decade;        decade = c[clen] / n; // 使用n进制         c[clen] %= n;    }    c[clen] = decade;    if(c[clen] == 0) clen--;    for(i = clen; i >= 1; i--) {        printf("%d", c[i]);    }     return 0;}

例题3

(本题来自NOIP1999提高组复赛试题,可以在Vijos查看此题,本题也是CCF官方教材入门篇P231练习第5题,Vijos提交记录AC)
若一个数(首位不为零)从左向右读与从右向左读都一样,我们就将其称之为回文数。
例如:给定一个10进制数56,将56加56(即把56从右向左读),得到121是一个回文数。
又如:对于10进制数87:
STEP1:87+78 = 165 STEP2:165+561 = 726
STEP3:726+627 = 1353 STEP4:1353+3531 = 4884
在这里的一步是指进行了一次N进制的加法,上例最少用了4步得到回文数4884。
写一个程序,给定一个N(2<=N<=10或N=16)进制数M,其中16进制数字为0-9与A-F,求最少经过几步可以得到回文数。如果在30步以内(包含30步)不可能得到回文数,则输出“Impossible!”

数据范围

2<=N<=10或N=16
0<=M<=maxlongint

输入输出

输入1

9
87

输出1

STEP=6

分析

本题由于进制不确定以及可能造成的数据过大,可以考虑采用例题2的高精度运算处理,可以使算法更加灵活。
注意:要特殊处理16进制。这里采用的是将16进制翻译成10进制,再翻译回16进制的处理方法。本题解不是最优解。(记得注释掉调试输出!)

实现

#include <cstdio>#include <cstring>#include <cctype>const int MAXN = 10001;int a[MAXN], b[MAXN], c1[MAXN];const char hex[] = "0123456789ABCDEF";// 高精度加法,返回结果的位数 int hplus(int n, char a1[], char b1[], char c[]) {    memset(a, 0, sizeof(a));    memset(b, 0, sizeof(b));    memset(c1, 0, sizeof(c1));    int alen = strlen(a1), blen = strlen(b1);    int i;    for(i = 0; i < alen; i++) a[alen - i] = isdigit(a1[i]) ? a1[i] - '0' : a1[i] - 'A' + 10;    for(i = 0; i < blen; i++) b[blen - i] = isdigit(b1[i]) ? b1[i] - '0' : b1[i] - 'A' + 10;    int clen, decade = 0;    for(clen = 1; clen <= alen || clen <= blen; clen++) {        c1[clen] = a[clen] + b[clen] + decade;        decade = c1[clen] / n;        c1[clen] = c1[clen] % n;        //printf("a %d b %d c1 %d\n", a[clen], b[clen], c1[clen]);    }    c1[clen] = decade;    if(c1[clen] == 0) clen--;    int j = 0;    for(i = clen; i >= 1; i--) {        //printf("i %d c1 %d\n", i, c1[i]);        c[j] = hex[c1[i]]; // 16进制         j++;    }    return clen;}void rev(char string[], char reved[]) {      int len = strlen(string);      int i;      for(i = 0; i < len; i++) {          reved[len - i - 1] = string[i];      }  }char input[MAXN], reved[MAXN], temp[MAXN];int main(void) {    //FILE *f = fopen("in.txt", "r");    int n;    scanf("%d%s", &n, input);    //fclose(f);    int i;    for(i = 0; i <= 30; i++) {        memset(reved, 0, sizeof(reved));        rev(input, reved);        //printf("input %s reved %s\n", input, reved);        if(!strcmp(input, reved)) {            printf("STEP=%d", i);            return 0;         }        hplus(n, input, reved, temp);        strcpy(input, temp);    }    printf("Impossible!");    return 0;}

三、总结

高精度加法(其实减法也可以用这样的思想去写)其实做了一件模拟手算列竖式的这样一个工作。但需要注意这里对char[]的复杂操作极容易写错,写这个算法的时候记着小心一些。

0 0
原创粉丝点击