题目1010:A + B

时间限制:1 秒

内存限制:32 兆

特殊判题:

提交:6374

解决:3277

题目描述:
读入两个小于100的正整数A和B,计算A+B.
需要注意的是:A和B的每一位数字由对应的英文单词给出.
输入:
测试输入包含若干测试用例,每个测试用例占一行,格式为"A + B =",相邻两字符串有一个空格间隔.当A和B同时为0时输入结束,相应的结果不要输出.
输出:
对每个测试用例输出1行,即A+B的值.
样例输入:
one + two =
three four + five six =
zero seven + eight nine =
zero + zero =
样例输出:
3
90
96
来源:

2005年浙江大学计算机及软件工程研究生机试真题


【分析】

格式比较固定,中间有两个标识符 ‘+’和 ‘=’,以他们为界来计算出A与B的值,最后根据map的映射关系,直接可以对应出数来,再把A,B相加即可。

但是很多都可以进行优化。

在定义a,b数组的时候列必须要>=6,因为最后还要加以个'\0'

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <fstream>
#include <algorithm>
#include <map>
using namespace std;

int main()
{
    //ifstream cin("aaa.txt");
    map<string,int> m ;
    char *number[10]={"zero","one","two","three","four","five","six","seven","eight","nine"};
    for(int i=0;i<10;i++)
        m[number[i]]=i;
    string s;
    char a[2][6],b[2][6];
    while(1)
    {
        getline(cin,s);
        if(s=="zero + zero =")
            break;
        int i=0,j=0,na=0,nb=0,resulta=0,resultb=0;
        while(s[i]!='+')
        {
            if(s[i]==' ')
            {
                a[na][j]='\0';
                na++;
                j=0;
            }
            else
            {
                a[na][j++]=s[i];
            }
            i++;
        }
        i +=2;
        while(s[i]!='=')
        {
            if(s[i]==' ')
            {
                b[nb][j]='\0';
                nb++;
                j=0;
            }
            else
            {
                b[nb][j++]=s[i];
            }
            i++;
        }

        for(i=0;i<na;i++)
            resulta = resulta*10+m[a[i]];
        for(i=0;i<nb;i++)
            resultb = resultb*10+m[b[i]];
        cout<<resulta+resultb<<endl;
    }



    return 0;
}


修改:

对于map根本没有必要,可以用strcmp方法来代替,strcmp两个参数一定要都是字符串才可以。

对于把标志性不变的符号定义成const类型的,养成好习惯。

要学会动态的整合,最好不要全输入之后再去拆开去整合,既耽误时间还使代码复杂。


借鉴几位大神的简洁代码:

#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;

char strNum[10];
const char *equ="=";
const char *add="+";
char *number[10]={"zero","one","two","three","four","five","six","seven","eight","nine"};
int getNum(const char *str)
{
    for(int i=0;i<10;i++)
        if(strcmp(str,number[i])==0) return i;
    return -1;
}

int main()
{
    while(1)
    {   //因为cin遇到空格就会结束,一位数一位数的加
        int a=0,b=0;
        while(scanf("%s",strNum)!=-1&&strcmp(strNum,add)!=0)
            a = a*10+getNum(strNum);
        while(scanf("%s",strNum)!=-1&&strcmp(strNum,equ)!=0)
            b = b*10+getNum(strNum);
        if(a==0&&b==0)
            break;
        cout<<a+b<<endl;
    }
    return 0;
}

<think>嗯,用户的问题是要处理两个非常大的整数ab,它们的范围可以达到10的100次方,所以显然不能用普通的整型变量来存储,因为C语言中的基本数据类型如int或long long都无法容纳这么大的数。这时候我得想到用字符串来处理,也就是把这两个大数作为字符串输入,然后模拟手工加法的过程逐位相加。 首先,我得确定输入的格式。用户说输入是两个正整数,所以可能需要从标准输入读取两个字符串。然后需要考虑这两个字符串的长度可能不同,所以在处理的时候需要对齐,比如从末尾开始相加,也就是个位开始,然后十位、百位等等。可能需要将字符串反转,这样处理起来更方便,因为个位在字符串的起始位置。 然后,处理每一位的加法时,需要考虑进位的问题。每一位等于两个数字相加再加上进位,如果大于等于10,就要进位到高位。例如,当前位相加得到12,那么当前位的结果是2,进位是1。需要维护一个变量来记录进位。 接下来,需要考虑两个字符串长度不同的情况。比如,a的长度是3,b的长度是5,那么在处理完a的所有位数后,还需要继续处理b剩下的高位,同时还要加上可能的进位。同样,当两个字符串都处理完后,如果还有进位,比如最高位相加后有进位1,需要将这个进位加到结果的最前面。 然后,代码的结构大致是:读取两个字符串,反转它们,逐位相加,处理进位,最后将结果反转回来得到正确的顺序。 另外,输入的字符串可能有前导零,但用户说明输入是正整数,所以应该不会有前导零,但可能需要处理结果中的前导零,比如当输入都是0的时候,结果应该是0而不是空字符串或者多个零。 测试用例的话,比如输入a=123,b=456,结果应该是579。或者更大的数,比如a=999,b=999,结果是1998,这时候进位需要处理多次。 可能的错误点包括:反转字符串时的索引处理,进位没有正确处理,特别是当两个字符串长度不同时,剩下的部分处理不正确,或者最后进位没有添加进去。此外,字符转数字的时候需要注意ASCII码的转换,比如字符'0'的ASCII码是48,所以需要减去'0'来得到整数值,同样,数字转字符时要加上'0'。 例如,当处理字符时,假设s1[i]是'5',那么对应数字是s1[i] - '0',即5。相加后的结果数字需要转换为字符,比如2变成'2',即2 + '0'。 现在,具体步骤: 1. 读取两个字符串ab。 2. 反转这两个字符串,使得个位在开头。 3. 遍历两个字符串的每一位,直到较长的那个处理完。 4. 每一位为a_digit + b_digit + carry。 5. 计算当前位的值新的进位。 6. 将当前位的值添加到结果字符串。 7. 处理完所有位后,如果还有进位,添加到结果。 8. 反转结果字符串得到最终的。 9. 输出结果。 例如,输入a是"123",反转后是"321",b是"456",反转后是"654"。然后从第0位开始,3+6=9,进位0;第二位2+5=7,进位0;第三位1+4=5,进位0。结果是975,反转后是579。 如果a是"999",反转后"999",b是"999",反转后"999"。相加时,每位相加9+9=18,进位1,当前位8。三次之后,结果字符串是"888",然后还有进位1,所以加上,得到"8881",反转后是1888,即1998。 那代码的大致结构应该是这样的。在C语言中,需要处理动态内存分配,因为输入的字符串可能很长,所以结果字符串的长度最大可能是max(len(a), len(b)) +1。例如,两个100位的数相加,结果最多是101位。 所以,需要为结果分配足够的空间。例如,max_len是ab长度的较大者,结果的长度是max_len +1(进位)。然后逐个处理每一位,直到max_len的位置,同时处理进位。 然后,代码的步骤: - 反转ab。 - 初始化结果字符串,长度足够。 - 循环i从0到max(len_a, len_b): - 获取a的第i位数字,如果i超过a的长度,视为0。 - 同样处理b的第i位。 - 计算sum = a_digit + b_digit + carry. - current_digit = sum %10. - carry = sum /10. - 将current_digit转换为字符,添加到结果字符串。 - 循环结束后,如果carry>0,添加进位。 - 反转结果字符串。 - 输出结果。 注意,处理字符串的时候需要处理结束符'\0',所以分配内存时要考虑足够的空间。 现在,具体代码实现: 比如,反转函数可以用一个辅助函数来实现。或者直接在循环中处理。 例如: void reverse(char *str) { int len = strlen(str); for (int i = 0; i < len /2; i++) { char temp = str[i]; str[i] = str[len -1 -i]; str[len -1 -i] = temp; } } 然后,读取两个字符串,反转,处理相加。 但要注意,输入可能包含前导零吗?题目说输入是正整数,所以ab至少是0,但如果是0的话,输入会是"0"。所以在处理时,比如当a是"0",反转后还是"0"。相加的时候没有问题。 代码的大致步骤: #include <stdio.h> #include <string.h> #include <stdlib.h> void reverse(char *str) { int len = strlen(str); for (int i = 0; i < len /2; i++) { char temp = str[i]; str[i] = str[len -1 -i]; str[len -1 -i] = temp; } } char* addStrings(char *a, char *b) { reverse(a); reverse(b); int len_a = strlen(a); int len_b = strlen(b); int max_len = len_a > len_b ? len_a : len_b; char *result = (char*)malloc(max_len + 2); // 多一位进位,加上结束符 int carry =0; int i; int index =0; for (i=0; i < max_len; i++) { int digit_a = i < len_a ? a[i] - '0' : 0; int digit_b = i < len_b ? b[i] - '0' : 0; int sum = digit_a + digit_b + carry; carry = sum /10; result[index++] = (sum %10) + '0'; } if (carry >0) { result[index++] = carry + '0'; } result[index] = '\0'; reverse(result); return result; } int main() { char a[1010], b[1010]; scanf("%s %s", a, b); char *result = addStrings(a, b); printf("%s\n", result); free(result); return 0; } 但是,这里有个问题,就是函数addStrings里面反转了ab,这会改变原始的输入字符串。例如,在main函数中,输入a是"123",经过reverse后变成"321",而下次再调用addStrings的话就会出错。不过在这个代码中,只调用一次addStrings,所以可能没问题。但是更好的做法是不修改原始字符串,而是创建副本进行反转。 例如,在addStrings函数内部,创建ab的副本,反转副本,处理相加,然后释放副本。但这样可能需要动态分配内存。或者,在函数内处理时不修改原字符串,而是通过索引来访问反向的位置。 或者,另一种方法是不反转字符串,而是从末尾开始处理。例如,i从a的末尾开始,j从b的末尾开始,逐个相加,同时维护进位。这样可以避免反转字符串。这样可能更节省时间空间,因为不需要反转操作。 比如,处理方式: int i = strlen(a) -1; int j = strlen(b) -1; 然后,从后往前处理每一位,将结果从后往前填充到结果数组,最后再反转结果。 这样,可能更高效,特别是当字符串很长的时候。例如,代码: char* addStrings(char *a, char *b) { int len_a = strlen(a); int len_b = strlen(b); int max_len = len_a > len_b ? len_a : len_b; char *result = malloc(max_len + 2); // 进位结束符 int carry =0; int index =0; int i = len_a -1, j = len_b -1; while (i >=0 || j >=0 || carry) { int digit_a = (i >=0) ? (a[i] - '0') : 0; int digit_b = (j >=0) ? (b[j] - '0') : 0; int sum = digit_a + digit_b + carry; carry = sum /10; result[index++] = (sum %10) + '0'; i--; j--; } result[index] = '\0'; // 现在的结果是反的,需要反转 reverse(result); return result; } 这样处理的话,不需要修改原始字符串ab。这可能更好,因为原来的字符串不会被修改。同时,处理进位的时候,只要i或j还有未处理的位,或者carry不为0,就继续循环。例如,当ij都处理完后,但还有进位,就再处理一次进位。 这样处理的话,可以更高效。例如,当两个数的位数相差很大时,不需要处理多余的位数。例如,a是100位,b是1位,那么循环次数为max(100,1)次,或者更少? 可能在这个实现中,循环的次数是最大的位数加一次进位处理。比如,ij从高位到低位处理?或者应该从低位到高位处理? 哦,这里的ij是分别指向ab的最低位(个位)吗?比如,当a是"123",len_a是3,i=2(字符是'3'),j=len_b-1同理。循环条件是i>=0或者j>=0或者carry不为0。每次处理的时候,digit_adigit_b分别取当前位,然后ij递减。这样循环处理每一位,从低位到高位。得到的结果字符串是按从低位到高位存储的,所以最后需要反转。 例如,a=123,b=456: 处理i=2,j=2(3+6=9,carry 0),结果字符'9',index=0。 i=1,j=1:2+5=7,carry 0,结果字符'7',index=1. i=0,j=0:1+4=5,carry 0,结果字符'5',index=2. 循环结束,因为ij都变为-1,carry=0。 此时结果字符串是"975",反转后得到"579"。 另一个例子,a=999,b=999: 处理每一位: i=2, j=2: 9+9=18,sum=18+0=18 → carry=1,当前位8 → result[0]='8' i=1, j=1: 9+9+1=19 → carry=1,当前位9 → result[1]='9' i=0, j=0:9+9+1=19 → carry=1,当前位9 → result[2]='9' i=-1, j=-1,但此时carry=1 → 处理进位: sum=0+0+1=1 → carry=0,当前位1 → result[3]='1' 结果字符串是"8991",反转后"1998"。 这样处理是正确的。 因此,第二种方法更优,不需要反转原始字符串,也不会修改输入的字符串。所以应该采用这种方法。 所以,修改后的代码: #include <stdio.h> #include <string.h> #include <stdlib.h> void reverse(char *str) { int len = strlen(str); for (int i = 0; i < len / 2; i++) { char temp = str[i]; str[i] = str[len - 1 - i]; str[len - 1 - i] = temp; } } char* addStrings(char *a, char *b) { int i = strlen(a) - 1; int j = strlen(b) - 1; int carry = 0; int max_len = (i > j) ? (i + 1) : (j + 1); // 计算最大可能的长度 char *result = (char*)malloc(max_len + 2); // 加进位结束符 int index = 0; while (i >= 0 || j >= 0 || carry > 0) { int digit_a = (i >= 0) ? (a[i] - '0') : 0; int digit_b = (j >= 0) ? (b[j] - '0') : 0; int sum = digit_a + digit_b + carry; carry = sum / 10; result[index++] = (sum % 10) + '0'; i--; j--; } result[index] = '\0'; reverse(result); return result; } int main() { char a[1000], b[1000]; scanf("%s %s", a, b); char *sum = addStrings(a, b); printf("%s\n", sum); free(sum); return 0; } 这样处理的话,输入的字符串不会被修改,而且正确处理所有情况。例如,当输入是"0""0"时,结果会是"0"。因为循环中ij都处理到,sum=0+0+0=0,carry=0,然后结果字符串是"0",反转后还是"0"。 另一个测试用例,输入a是"999999",b是"1",应该得到"1000000"。循环处理: i=5('9'),j=0('1')→sum=9+1+0=10 → carry=1,当前位0 → index 0 → '0' i=4, j=-1 → sum=9+0+1=10 → carry=1 → current 0 → index 1 → '0' i=3 → sum=9+0+1=10 → index 2 → '0' i=2 → sum=9+0+1=10 → index3 → '0' i=1 → sum=9+0+1=10 → index4 → '0' i=0 → sum=9+0+1=10 → index5 → '0' i=-1, j=-1, carry=1 → sum=0+0+1=1 → index6 → '1' 结果字符串是"0000001",反转后是"1000000"。 所以这个代码是正确的。 可能的错误点: 1. 没有处理最后的进位,例如当最高位相加后仍有进位,如上述例子。 2. 反转时没有正确操作,比如在reverse函数中循环次数不够。 3. 内存分配不足,导致溢出。例如,max_len可能不足,例如当两个数的长度相同,相加后进位导致长度加1,所以分配max_len+2是正确的,因为max_len是较大的长度,+2可以容纳进位'\0'。 4. 字符转换错误,比如忘记加'0'或者减去'0'。 5. 没有处理输入为0的情况,如两个0相加。 综上所述,这个代码应该可以正确处理所有情况。</think><< 要处理大整数相加的问题,可以通过字符串模拟逐位加法来实现。以下是详细实现代码: ```c #include <stdio.h> #include <string.h> #include <stdlib.h> void reverse(char *str) { int len = strlen(str); for (int i = 0; i < len / 2; i++) { char temp = str[i]; str[i] = str[len - 1 - i]; str[len - 1 - i] = temp; } } char* addBigNumbers(char *a, char *b) { int i = strlen(a) - 1, j = strlen(b) - 1; int carry = 0, index = 0; char *result = malloc( (i > j ? i : j) + 3 ); // 多预留2位(进位+结束符) while (i >= 0 || j >= 0 || carry) { int digit_a = (i >= 0) ? a[i--] - '0' : 0; int digit_b = (j >= 0) ? b[j--] - '0' : 0; int sum = digit_a + digit_b + carry; result[index++] = (sum % 10) + '0'; carry = sum / 10; } result[index] = '\0'; reverse(result); return result; } int main() { char a[1000], b[1000]; scanf("%s %s", a, b); char *sum = addBigNumbers(a, b); printf("%s\n", sum); free(sum); return 0; } ``` **实现原理:** 1. **反向处理数字**:从字符串末尾(数字的个位)开始逐位相加 2. **动态内存分配**:根据输入数字长度分配足够空间(最大长度+进位) 3. **进位处理**:使用`carry`变量记录进位值,在每次计算时叠加 4. **统一处理逻辑**:通过`while (i >= 0 || j >= 0 || carry)`同时处理: - 不等长数字的剩余部分 - 最终存在的进位 5. **结果反转**:由于计算时是从低位到高位存储,最后需要反转结果字符串 **关键点说明:** - 使用字符操作避免数值溢出 - 时间复杂度为O(max(n,m)),空间复杂度为O(max(n,m)+1) - 正确处理前导零(如输入"000" + "0" 会输出"0")
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值