题目来源:http://cxsjsxmooc.openjudge.cn/test/D/
D:大整数的加减乘除
总时间限制: 1000ms 内存限制: 65536kB
描述
给出两个正整数以及四则运算操作符(+ - * /),求运算结果。
输入
第一行:正整数a,长度不超过100
第二行:四则运算符o,o是“+”,“-”,“*”,“/”中的某一个
第三行:正整数b,长度不超过100
保证输入不含多余的空格或其它字符
输出
一行:表达式“a o b”的值。
补充说明:
1. 减法结果有可能为负数
2. 除法结果向下取整
3. 输出符合日常书写习惯,不能有多余的0、空格或其它字符
样例输入
9876543210
+
9876543210
样例输出
19753086420
------------------------------------------------------------
题意
C++高精度,限定输入为正整数(只有减法结果可能产生负数)
------------------------------------------------------------
思路
【数据结构】
用字符串表示大整数。
【减法】
由于“小数 – 大数”会产生负数,为避免直接处理“小数 – 大数”的情况,首先写一个大整数的比较函数,然后根据减数和被减数的大小比较结果将“小数 – 大数”化为“大数 – 小数”,并在结果之前添上一个负号。
【乘法/除法】
记被乘/除数和乘/除数分别为a/b. 如果直接将乘法化为加法(乘数个被乘数相加)、将除法化为减法(被除数减除数的次数),则乘法复杂度为O(b(log(a)+log(b))),除法复杂度为O((a/b)log(a)),对于大整数来说,b和a/b都可能是极大的数(可达10^100),这样肯定会超时。
正确的算法是模仿竖式乘/除法。竖式乘法的复杂度为O(log(a)log(b)(log(a)+log(b))),竖式除法的复杂度为O((log(a)-log(b))log(a)).
------------------------------------------------------------
代码
/*
正整数大数类的加减乘除
http://cxsjsxmooc.openjudge.cn/test/D/
*/
#include<string>
#include<iostream>
#include<algorithm>
void reverse_string(std::string &ans)
{
int n = ans.length(), i;
char tmp;
for (i=0; i<n/2; i++)
{
tmp = ans.at(i);
ans.at(i) = ans.at(n-i-1);
ans.at(n-i-1) = tmp;
}
}
void remove_zeros(std::string &ans)
{
if (ans == "0")
{
return;
}
int i = 0;
for (i=0; i<ans.length(); i++)
{
if (ans.at(i) != '0')
{
break;
}
}
ans = ans.substr(i);
}
class BigInt {
public:
std::string num; // unsigned number
BigInt(void) {}
BigInt(std::string Num): num(Num) {}
BigInt Add(const BigInt & b)
{
std::string ans;
int i, n1 = std::min(num.length(), b.num.length()), n2 = std::max(num.length(), b.num.length()), a1, a2, s = 0, si = 0;
for (i=0; i<n1; i++)
{
a1 = num.at(num.length()-i-1) - '0';
a2 = b.num.at(b.num.length()-i-1) - '0';
if (a1 + a2 + si< 10)
{
s = a1 + a2 + si;
si = 0;
}
else
{
s = (a1 + a2 + si) - 10;
si = 1;
}
ans.push_back((char)(s + '0'));
}
for (i=n1; i<n2; i++)
{
if (n2 == num.length())
{
a1 = num.at(n2-i-1) - '0';
}
else
{
a1 = b.num.at(n2-i-1) - '0';
}
if (a1 + si < 10)
{
s = a1 + si;
si = 0;
}
else
{
s = (a1 + si) - 10;
si = 1;
}
ans.push_back((char)(s + '0'));
}
if (si == 1)
{
ans.push_back('1');
}
reverse_string(ans);
return BigInt(ans);
}
int Compare(const BigInt & b) // -1: < 0: == 1: >
{
int n1 = num.length(), n2 = b.num.length(), i = 0;
if (n1 > n2)
{
return 1;
}
else if (n1 < n2)
{
return -1;
}
else
{
for (i=0; i<n1; i++)
{
if (num.at(i) > b.num.at(i))
{
return 1;
}
else if (num.at(i) < b.num.at(i))
{
return -1;
}
}
return 0;
}
}
BigInt Subtract(const BigInt & b)
{
std::string ans;
int oper = Compare(b), i, n1 = num.length(), n2 = b.num.length(), a1, a2, s = 0, si = 0;
if (oper == 0)
{
return BigInt("0");
}
else if (oper == -1)
{
n1 = b.num.length();
n2 = num.length();
for (i=0; i<n2; i++)
{
a1 = b.num.at(n1-i-1) - '0';
a2 = num.at(n2-i-1) - '0';
if (a1 - a2 - si >= 0)
{
s = a1 - a2 - si;
si = 0;
}
else
{
s = (a1 - a2 - si) + 10;
si = 1;
}
ans.push_back((char)(s + '0'));
}
for (i=n2; i<n1; i++)
{
a1 = b.num.at(n1-i-1) - '0';
if (a1 - si >= 0)
{
s = a1 - si;
si = 0;
}
else
{
s = (a1 - si) + 10;
si = 1;
}
ans.push_back((char)(s + '0'));
}
reverse_string(ans);
remove_zeros(ans);
std::string ans1 = "-";
ans = ans1.append(ans);
}
else
{
for (i=0; i<n2; i++)
{
a1 = num.at(n1-i-1) - '0';
a2 = b.num.at(n2-i-1) - '0';
if (a1 - a2 - si >= 0)
{
s = a1 - a2 - si;
si = 0;
}
else
{
s = (a1 - a2 - si) + 10;
si = 1;
}
ans.push_back((char)(s + '0'));
}
for (i=n2; i<n1; i++)
{
a1 = num.at(n1-i-1) - '0';
if (a1 - si >= 0)
{
s = a1 - si;
si = 0;
}
else
{
s = (a1 - si) + 10;
si = 1;
}
ans.push_back((char)(s + '0'));
}
reverse_string(ans);
remove_zeros(ans);
}
return BigInt(ans);
}
BigInt Multiply(const BigInt & b)
{
BigInt ans("0");
std::string tmp;
int i, j, k, n1 = num.length(), n2 = b.num.length(), a1, a2, s = 0, si = 0;
for (j=n2-1; j>=0; j--)
{
a2 = b.num.at(j) - '0';
if (a2 == 0)
{
continue;
}
tmp.clear();
s = 0;
si = 0;
for (k=0; k<n2-1-j; k++)
{
tmp.push_back('0');
}
for (i=n1-1; i>=0; i--)
{
a1 = num.at(i) - '0';
s = (a1 * a2 + si) % 10;
si = (a1 * a2 + si) / 10;
tmp.push_back((char)(s + '0'));
}
if (si != 0)
{
tmp.push_back((char) (si + '0'));
}
reverse_string(tmp);
ans = ans.Add(BigInt(tmp));
}
return ans;
}
BigInt Divide(const BigInt & b)
{
std::string ans;
BigInt div;
int n1 = num.length(), n2 = b.num.length(), i, tmp = 0;
if (n1 < n2)
{
return BigInt("0");
}
div.num = num.substr(0, n2-1);
for (i = 0; i <= n1 - n2; i++)
{
div.num.push_back(num.at(i+n2-1));
tmp = 0;
while (div.Compare(b) >= 0)
{
tmp++;
div = div.Subtract(b);
}
ans.push_back((char) (tmp + '0'));
}
remove_zeros(ans);
return BigInt(ans);
}
};
int main()
{
BigInt a,b;
char oper;
std::cin >> a.num >> oper >> b.num;
switch (oper)
{
case '+':
std::cout << a.Add(b).num;
break;
case '-':
std::cout << a.Subtract(b).num;
break;
case '*':
std::cout << a.Multiply(b).num;
break;
case '/':
std::cout << a.Divide(b).num;
break;
default: break;
}
return 0;
}