算法竞赛入门经典高精度运算推荐题目

题目

OriginTitleSatus
UVA 424Integer InquiryAC
UVA 10106ProductAC
UVA 465OverflowAC
UVA 748ExponentiationAC
UVA 10494If We Were a Child AgainAC

UVA 424 Integer Inquiry

分析

  1. 大数相加可以通过模拟来实现,即两大数从个位起逐位数字相加,相加得到的数字范围在[0, 18]之间,再与结果集当前位相加(此时范围应在[0,19]之间),取十位置入结果集的进一位,取个位置入结果集的本位.

       1 2
     + 8 9
     —————-
        (0)11
        1
       (1)9
       0
     (1)
     1
     —————-
     1 0 1

  2. 由上述可知,将大数倒序存储是一个好的选择.

  3. 此外,为了方便地输入,较多使用字符数组存储,在做数字运算时,切勿忘记-‘0’以获得数字.
  4. 还有一件事,高精度运算类的题目在调试时,可以尝试输出中间量,以检查算法是否正确.
  5. 还有一件事,因为是倒序存储,那么前导0是必须处理的,可以从结果集的最高位向下减小直到当前位不是0,也可以设置一个最高位索引(注意进位时索引也要增加). 从此位倒序输出倒序数组,即获得无前导0的正序大数.

代码

#include <stdio.h>
#include <string.h>

int main(void)
{
    char cn[120];
    int in[120], i, j, k;
    memset(in, 0, sizeof(in));
    while (fgets(cn, 120, stdin) && cn[0] != '0') {
        for (i = strlen(cn)-2, j = 0; i >= 0; i--, j++) {
            in[j] = in[j] + (cn[i] - '0');
            k = j;
            while (in[k++] > 9) {
                in[k] += in[k-1]/10;
                in[k-1] %= 10;
            }
        }
    }
    for (i = 120-1; in[i] == 0; i--);
    for (; i >= 0; i--)
        printf("%d", in[i]);
    printf("\n");
    return 0;
}

UVA 10106 Product

分析

  1. 大数乘法,可以模拟.

       1 2
     × 1 2
     —————-
        (0)4
        4
       (0)2
       2
       (2)2
       4
     (0)1
     1
     —————-
     1 4 4

  2. 建议将较大的数组放入全局区,避免RE(Runtime error)嗯.

代码

#include <stdio.h>
#include <string.h>

int main(void)
{
    char a[300], b[300];
    int r[90000], x[300], y[300];
    int i, j, k;
    while (fgets(a, 300, stdin), fgets(b, 300, stdin)) {
        memset(x, 0, sizeof(x));
        memset(y, 0, sizeof(y));
        memset(r, 0, sizeof(r));
        for (i = strlen(a)-2, j = 0; i >= 0; i--, j++) x[j] = a[i] - '0';
        for (i = strlen(b)-2, j = 0; i >= 0; i--, j++) y[j] = b[i] - '0';
        for (i = 0; i < strlen(a)-1; i++)
            for (j = 0; j < strlen(b)-1; j++) {
                r[i+j] += x[i] * y[j];
                if (r[i+j] > 9) {
                    r[i+j+1] += r[i+j]/10;
                    r[i+j] = r[i+j]%10;
                }
            }
        for (k = i * j; r[k] == 0 && k > 0; k--);
        for (; k >= 0; k--) printf("%d", r[k]); printf("\n");
    }
    return 0;
}

UVA 465 Overflow

分析

  1. int有点小,会溢出,换double问题解决(并不是适用于所有情况,比如可能会影响到精度问题)~
  2. 关于int的范围可以参见<limits.h>.
    /* Minimum and maximum values a `signed int’ can hold. */
    # define INT_MIN (-INT_MAX - 1)
    # define INT_MAX 2147483647

代码

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    char fs[600], ss[600], op;
    double f, s, r;
    while (scanf("%s %c %s", fs, &op, ss) != EOF) {
        printf("%s %c %s\n", fs, op, ss);
        f = atof(fs);
        s = atof(ss);
        if (op == '*') r = f * s;
        if (op == '+') r = f + s;
        /* 2^31 - 1 */
        if (f > 2147483647) printf("first number too big\n");
        if (s > 2147483647) printf("second number too big\n");
        if (r > 2147483647) printf("result too big\n");
    }
    return 0;
}

UVA 748 Exponentiation

分析

  1. k次幂,可以把它当作k次乘法,一个数的第i(i = 0, 1, 2, … , k-1)次幂与其本身相乘.
  2. 本题的数据带有小数点,但是小数点可以在计算时忽略,为什么呢?因为小数点的移动步长是可以推算的,无需在计算时带入.
  3. 注意前导0后导0.

代码

#include <stdio.h>
#include <string.h>

int res[310], num[6], numc[310];

void cal_exp(int n)
{
    int i, j;
    /* base */
    if (n == 1)
        return;

    for (i = 0; i < 5; i++) {
        for (j = 0; j < 300; j++) {
            numc[i+j] += num[i] * res[j];
            if (numc[i+j] > 9) {
                numc[i+j+1] += numc[i+j]/10;
                numc[i+j] = numc[i+j]%10;
            }
        }
    }
    for (i = 0; i < 310; i++) {
        res[i] = numc[i];
        numc[i] = 0;
    }

    cal_exp(n-1);
}

int main(void)
{
    char tmp[6], r[310];
    int i, j, k, n, pos;
    while (scanf("%s%d", tmp, &n) == 2) {
        memset(num, 0, sizeof(num));
        memset(res, 0, sizeof(res));
        for (i = 5, j = 0; i >= 0; i--) {
            if (tmp[i] != '.') {
                res[j] = tmp[i] - '0';
                num[j++] = tmp[i] - '0';
            } else {
                pos = 5-i;
            }
        }
        memset(numc, 0, sizeof(numc));
        memset(r, '\0', sizeof(r));
        cal_exp(n);
        for (k = 0, i = 0; res[i]==0; i++, k++);
        for (j = 0; i < 310; i++) {
            if (k == n * pos) r[j++] = '.';
            r[j++] = res[i] + '0';
            k++;
        }
        for (i = 310-1; r[i] == 0 || r[i] == 48; i--);
        for (; i >=0; i--)
            printf("%c", r[i]);
        printf("\n");
    }
    return 0;
}

UVA 10494 If We Were a Child Again

分析

  1. 小数除大数,大数除以小数,模拟走起,被除数从最高位起,向下一位取数,再除以除数,得到的即是商,最后被除数位数排满了,即再做除法运算将获得小数的数即为余数.

      _________
     12 ) 1 4 5
      (0)1 / 12 = 0 …… (1)
       (1)4 / 12 = 1 …… (2)
        (2)5 / 12 = 2 …… [1]

      _0__1__2_ …… 1
     12 ) 1 4 5

  2. 重要的事情记三遍0

代码

#include <stdio.h>
#include <string.h>
#define MAXN 1005

char a[MAXN], c, div[MAXN];
long b, mod;

void cal(void)
{
    int i;
    long long n = 0;
    for (i = 0; i < strlen(a); i++) {
        n = n*10 + (a[i] - '0');
        div[i] = (n / b) + '0';
        n = n % b;
    }
    mod = n;
    return;
}

int main(void)
{
    int i;
    while (scanf("%s", a) == 1) {
        while ((c = getchar()) == ' ');
        scanf("%lld", &b);
        memset(div, '\0', sizeof(div));
        cal();
        if (c == '/') {
            for (i = 0; div[i]=='0' && i < strlen(div)-1; i++);
            for (; i < strlen(div); i++)
                printf("%c", div[i]); 
            printf("\n"); 
        } else if (c == '%') {
            printf("%lld\n", mod); 
        }
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值