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.youkuaiyun.com/jcwkyl/article/details/4090837

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

7-3 Manhattan(c++题解,代码无注释) 分数 35 作者 DAI, Longao 单位 杭州百腾教育科技有限公司 m.jpg Manhattan is a board game where players gain scores by building skyscrapers(摩天大楼)with blocks of heights 1, 2 or 3 on the table. After adding a block to an existing skyscraper, the total height of a player's blocks in this skyscraper must not be lower than the total height of any other players' blocks in this same skyscraper. For the sake of simplicity, let's assume that only two players are playing the game and they add blocks to the only skyscraper. Also there are infinite blocks of each type. Let sequence A=a 1 ​ ,a 2 ​ ,⋯,a n ​ (1≤a i ​ ≤3) be the heights of blocks added to the skyscraper in order and sequence B=b 1 ​ ,b 2 ​ ,⋯,b n ​ (b i ​ ∈{1,2}) be the indices of the players adding the corresponding blocks. After the game, however, sequence B is lost and only sequence A remains. Please calculate the number of different sequence B's so that the building procedure of the skyscraper does not break the game rules. Note that two sequences b 1 ​ ,b 2 ​ ,⋯,b n ​ and b 1 &prime; ​ ,b 2 &prime; ​ ,⋯,b n &prime; ​ of length n are different if there exists an integer k such that 1≤k≤n and b k ​  =b k &prime; ​ . Input The first line contains an integer n (1≤n≤10 5 ) indicating the number of blocks in the skyscraper. The second line contains n integers a 1 ​ ,a 2 ​ ,⋯,a n ​ (1≤a i ​ ≤3) indicating the heights of the blocks added to the skyscraper in order. Output Output in one line an integer indicating the number of different sequence B's. As the answer might be large, please print the answer modulo (10 9 +7). Sample Input 1 3 1 3 3 Sample Output 1 6 Sample Input 2 10 1 1 1 1 1 1 1 1 1 1 Sample Output 2 94 Hint For the first sample test case, the possible sequences are [1,1,1], [1,2,1], [1,2,2], [2,1,1], [2,1,2] and [2,2,2]. [1,1,2] is invalid because after the 2nd player builds the 3rd block, the total height of his blocks is 3, which is lower than the total height of blocks of the 1st player (which is 4). [2,2,1] is also invalid in the similar way. 代码长度限制 16 KB Java (javac) 时间限制 600 ms 内存限制 128 MB 其他编译器 时间限制 200 ms 内存限制 128 MB 栈限制 131072 KB
最新发布
08-13
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值