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

来源:互联网 发布:淘宝上1元秒杀是真的吗 编辑:程序博客网 时间:2024/04/30 12:04

题目

Origin Title Satus UVA 424 Integer Inquiry AC UVA 10106 Product AC UVA 465 Overflow AC UVA 748 Exponentiation AC UVA 10494 If We Were a Child Again AC

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 1005char 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 0