Uva 10494 - If We Were a Child Again(大数相除)
Problem C
If We Were a Child Again
Input: standard input
Output: standard output
Time Limit: 7 seconds
“Oooooooooooooooh!
If I could do the easy mathematics like my school days!!
I can guarantee, that I’d not make any mistake this time!!”
Says a smart university student!!
But his teacher even smarter – “Ok! I’d assign you such projects in your software lab. Don’t be so sad.”
“Really!!” - the students feels happy. And he feels so happy that he cannot see the smile in his teacher’s face.
The Problem
The first project for the poor student was to make a calculator that can just perform the basic arithmetic operations.
But like many other university students he doesn’t like to do any project by himself. He just wants to collect programs from here and there. As you are a friend of him, he asks you to write the program. But, you are also intelligent enough to tackle this kind of people. You agreed to write only the (integer) division and mod (% in C/C++) operations for him.
Input
Input is a sequence of lines. Each line will contain an input number. One or more spaces. A sign (division or mod). Again spaces. And another input number. Both the input numbers are non-negative integer. The first one may be arbitrarily long. The second number n will be in the range (0 < n < 231).
Output
A line for each input, each containing an integer. See the sample input and output. Output should not contain any extra space.
Sample Input
110 / 100
99 % 10
2147483647 / 2147483647
2147483646 % 2147483647
Sample Output
1
9
1
2147483646
1 #include<stdio.h> 2 #include<string.h> 3 #define MAXN 1002 4 int a[MAXN], c[MAXN], last[MAXN]; // a是存储整型的被除数,c是存储得数,last存储的是每次相除后(其实是相减)的余数 5 char s[MAXN]; //存储输入的被除数 6 7 int dealb(int (*b)[20], char *d) 8 {// 求出 除数*n 的每个值并存于数组b中(n = 1 2 3 4 ..... 9) 9 int len = strlen(d), i, j, e, temp, t; 10 for(i=0; i<len; ++i) 11 for(j=1; j<10; ++j) 12 b[j][i+1] = d[len-1-i] - '0'; 13 b[1][0] = len; 14 15 for(i=2; i<10; i++) 16 {//大数相乘 17 e = 0; 18 for(t=1; t<len+1; ++t) 19 { 20 temp = i*b[i][t] + e; 21 b[i][t] = temp%10; 22 e = temp/10; 23 } 24 if(e) b[i][t++] = e; 25 b[i][0] = t-1; 26 } 27 return 0; 28 } 29 30 int cmp(int (*b)[20], int n) 31 {// 从上到下筛选dealb函数得到的数组,返回的值是得数的依次低位数, 32 //n存储的是余数数组或者说除数依次高位向下的数个数和最高下标 33 int i, j, temp, t, k, flag; 34 for(k=0; k<n && last[k]==0; ++k); 35 for(i=9; i>0; --i) 36 { 37 // 两个数比较的三种情况 38 if(b[i][0] > n-k+1) continue; // 位数不相同情况之一,减数较大则继续找下一位 39 if(b[i][0] < n-k+1) return i; // 位数不相同情况之二,减数较小则返回减数的所在的下标,这个值也是得数的当前最低位数 40 for(j=b[i][0],t=k,flag=0; t<=n && j>0 && b[i][j] == last[t]; ++t, --j) //位数相同的,逐个位权的数进行比较 41 ; 42 if(t>n || j<=0 || b[i][j] < last[t]) return i; 43 } 44 return 0; 45 } 46 47 int main() 48 { 49 int i, j, k, t, len, flag, temp, count = 0, loc, e, h; 50 int b[12][20]; // b[i]存储的除数*i的值(i=1 2 3...9),每个第一位即b[i][0]存储该值的长度 51 char opt, d[20]; 52 while(scanf("%s", s) != EOF) 53 { 54 while((opt = getchar()) == ' '); 55 scanf("%s", d); 56 dealb(b, d); 57 len = strlen(s); 58 for(i=0; i<len; ++i) a[i] = s[i] - '0'; 59 count = loc = h = 0; 60 for(i=0; i<len; ++i) 61 { 62 last[count++] = a[i]; 63 if((loc = cmp(b, count-1)) != 0) 64 { 65 for(t=count-1,j=1,e=0; t>=0 && j<=b[loc][0]; --t, ++j) 66 {// 从cmp得到的信息保证了b[1oc] - last >=0,此处进行相减运算 67 if((temp = last[t]-b[loc][j] + e) < 0) 68 { 69 e = -1; 70 last[t] = 10 + temp; 71 } 72 else 73 { 74 e = 0; 75 last[t] = temp; 76 } 77 } 78 if(j>b[loc][0] && t>=0) 79 { 80 for(; t>=0; --t) 81 { 82 temp = last[t] + e; 83 if(temp < 0) e = -1, last[t] = 10+temp; 84 else e = 0, last[t] = temp; 85 } 86 } 87 88 } 89 c[h++] = loc; 90 } 91 if(opt == '/') 92 { 93 for(i=0; i<h-1 && c[i] == 0; ++i); // 除去前缀零 94 for(; i<h; ++i) printf("%d", c[i]); 95 } 96 97 else 98 { 99 for(i=0; i<count-1 && last[i] == 0; ++i); 100 for(; i<count; ++i)printf("%d", last[i]); 101 } 102 printf("\n"); 103 } 104 return 0; 105 }
1Wa
解题思路:
大数的运算主要是根据笔算的步骤用代码实现,不管是乘法、加法、减法都不例外,下面说说大数相除的思路:
变量声明:
便于理解,首先为每个变量设一个字符(根据我的代码)
被除数:a (存储从左至右 即 xxx... = a[0]a[1]a[2]....)
除数:b[1] (存储从右至左 即 xxx... = b[1][n]b[n-1][n-2]... 长度n=b[1][0])同样可以理解 b[m](m = 1 2 3 4...9) = b[1] * m;
商: c (存储从左至右 即xxx... = c[0][1][2]...)输出时应该省略掉前缀无意义的0
余数/次被除数:last (存储从左至右 ) 根据除法的运算可知,每次要得到商上的一个数字时,都要进行一次减法的运算,有时得到的0,有时得到的小于除数的值,而到最后时它的 身份是余数而已; 同时,每次得到商的一个数字时,如果last有非零数时,它必须再和被除数的下一权值上的数进行组合(运算)可描述为:last = last*10 + n 然后进行相除
步骤:
1. 根据除数求出 1~9倍的数
2. 开始截取被除数的高到低的位数并存储到last数组中,比如说 a = 1234 则第一次截取的数为last = 1,在cmp函数中找到需要的那个数(其实也是商中所对应的位置的值),比如说设除数 b1 = 10; 则 b2 = 20, b3 = 30 ... b9 = 90; 从b9->b1从高到低找,直到找到 last - bn > 0 且最接近0的那个数bn,并返回n,这时保证了符合两数相减且合适差最小的条件
3. 将返回的n存储到商中,并进行第2步说的相减运算,将差放入余数last中
4. 在除数中继续截取目前高位的数字,这次是 a 中的 2,并接到last值得后面,变成次被除数last,这时last的值变成 12 ,然后继续调用cmp函数, 即转到步骤2,继续运算求值
5. 最后根据题目要求输出需要printf的值,输出时省略无意义的0
更多内容请关注个人微信公众号 物役记 (微信号:materialchains)