calculate the answer of a + b

   这是一道acm练习题,原题见“北京理工大学2012年ACM寒假练习题”,http://acm.bit.edu.cn/mod/programming/view.php?a=485

Problem Description
Now let’s calculate the answer of a + b ~
Input
The input will consist of a set of pairs of integers for a and b(-10^1000 <= a, b <= 10^1000). The input is ended by EOF.
Output
For each test case you should output the answer of a + b.
Sample Input
1 1
1 -1
Sample Output
2

0

   看是很简单的题目,确花费了我一个晚上的时间才解出来,关键问题是:

     1.这里面输入的数字远远超过了整形数据的最大范围,要求是-10^1000 <= a, b <= 10^1000,所以只能用字符串表示数字,就涉及到大整数运算问题
     2.所有的测试用例都是隐藏的,我们看不到,所以必须考虑到所有可能的情况,比如 +0、-0、+123......
     3.写好的程序可以在线提交http://acm.bit.edu.cn/mod/programming/submit.php?a=485,这里是在线评测系统,有内存和计算时间限制(不能超过1s)

    以下是本人的程序,仅供参考,速度有些低,算法很粗超,时间紧迫就没有添加注释,而且后期会做重大优化:

#include "stdafx.h" #include <windows.h> #include <string> #include <iostream> #include <vector> using namespace std; string AddNum(string sign, string a, string b)//加法运算,第一个参数表示结果符号,后两个为操作数 { int carry = 0, i, j, k = -1;//carry表示进位标志位 if (sign == "-")//两个负数,则第0位为符号位 k = 0; if (a.length() < b.length()) //a中始终存放最长的那个字符串 { string tem = a; a = b; b = tem; } for (i = a.length() - 1, j = b.length() - 1; i >= k + 1 ; i--)//从尾向头计算 { int n = (a[i] - '0') + ((j != k) ? (b[j--] - '0') : 0); int d = carry + n; if (d > 9) { carry = 1; //满10进1 d = d - 10; } else carry = 0; a[i] = d + '0'; //结果依然存放在a中 } return (carry == 1 ? sign + "1" + a.substr(k + 1) : sign + a.substr(k + 1)); } string Subtract(string a, string b) { string result = " "; int i; int f = 0; string flag = "0"; if (a[0] == '-') { a = a.substr(1); int le = a.length() - b.length(); if (le < 0) { for (i = 0; i < -1 * le; i++) { a.insert(0,"0"); } } if (le > 0) { for (i = 0; i < le; i++) { b.insert(0,"0"); } flag = "-"; } if (a == b) { return "0"; } if (a < b) { flag = "0"; string tem = a; a = b; b = tem; } else flag = "-"; } else { b = b.substr(1); int le = a.length() - b.length(); if (a == b) { return "0"; } if (le < 0) { for (i = 0; i < -1 * le; i++) { a.insert(0,"0"); } flag = "-"; string tem = a; a = b; b = tem; } else if (le > 0) { for (i = 0; i < le; i++) { b.insert(0,"0"); } flag = "0"; } else { if (a < b) { flag = "-"; string tem = a; a = b; b = tem; } else flag = "0"; } } result = result + a; for (i = a.length() - 1; i >= 0; i--) { if (a[i] < '0' || a[i] > '9' || b[i] < '0' || b[i] > '9') { return "error"; } int n = (a[i] - '0') - (b[i] - '0'); int d = f + n; if (d < 0) { f = -1; d = d + 10; } else f = 0; result[i+1] = d + '0'; } int m ; for (m = 1; result[m] == '0'; m++); result = result.substr(m); if (flag[0] == '0') return result; else return flag[0] + result; } string Calculate(string a, string b) //计算入口 { if (a[0] != '-' && b[0] != '-') //如果是两个正数,符号位置为空 return AddNum("",a,b); else if (a[0] == '-' && b[0] == '-') //如果是两个负数,符号位置为"-" return AddNum("-",a,b); else //两个异号数,执行减法运算 return Subtract(a,b); } int main() { string a,b; vector<string> v; unsigned int i = 0; while (cin>>a) v.push_back(a); while(i < v.size()) { cout<<Calculate(v[i], v[i+1])<<endl; i = i + 2; } system("pause"); return 0; }

2012-4.28编辑:

上面的算法有个最大的弊端就是运行需要占很大的内存,而且时间复杂度很好,但是易于理解,经过与其他同学的交流发现了一种更加简洁的方法:利用补码运算实现大数加法,其原理是模拟二进制补码运算,因为二进制数的减法可以通过对其补码求和实现,这样就可以把减法转换为加法运算,节省了大量的代码,也降低了时间复杂度和空间复杂度,请看代码:

#include "stdafx.h" #include <windows.h> #include <iostream> #include <stdio.h> #include <string.h> using namespace std; #define MAX 1010 char a[MAX+1]; char b[MAX+1]; char tem[MAX]; char sum[MAX+1]; void trans(char *a)//求十进制补码,最大数位1010 { int i, x = 0; for (i = MAX; ~i; --i) { a[i] = x - a[i]; x = -(a[i] < 0); if (a[i] < 0) a[i] += 10; } cout<<a<<endl; } void plus(const char *a, const char *b, char *sum) { int i, x = 0; for (i = MAX; ~i; --i) //对a和b的补码相加 { sum[i] = a[i] + b[i] + x; x = sum[i] >= 10; if (sum[i] >= 10) sum[i] -= 10; } } void output(char *a) { int i; if(a[0] == 9)//表示结果是个负数 { trans(a);//负数的补码即为原码 putchar('-'); } for (i = 1; i < MAX && !a[i]; ++i); while (i <= MAX) putchar(a[i++] + '0'); putchar('\n'); } int input(char *a) { int i, j = MAX; memset(a, 0, (MAX+1)*sizeof(char)); if(scanf("%s", tem)==EOF) return 0; for(i = strlen(tem) - 1; ~i && tem[i]!='-' ; i--) { a[j--] = tem[i] - '0'; } if(tem[0]=='-')trans(a); //如果是负数,求其补码 return 1; } int main() { while(input(a)&&input(b)) { plus(a, b, sum); output(sum); } system("pause"); return 0; }
更详细的原理请参考 http://blog.csdn.net/jcwkyl/article/details/4090837

。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。上课去了再见

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值