PAT乙级1011

1011 A+B 和 C

给定区间 [−2​31,231] 内的 3 个整数 A、B 和 C,请判断 A+B 是否大于 C。

输入格式:
输入第 1 行给出正整数 T (≤10),是测试用例的个数。随后给出 T 组测试用例,每组占一行,顺序给出 A、B 和 C。整数间以空格分隔。

输出格式:
对每组测试用例,在一行中输出 Case #X: true 如果 A+B>C,否则输出 Case #X: false,其中 X 是测试用例的编号(从 1 开始)。

输入样例:
4
1 2 3
2 3 4
2147483647 0 2147483646
0 -2147483648 -2147483647

输出样例:
Case #1: false
Case #2: true
Case #3: true
Case #4: false

要点:
long long的范围是完全可以的,这很简单就不赘述了。
分享一下使用字符串模拟加法的方式,因为我不想再单独写一个减法函数,所以利用计算机编码中补码的思想,减法变为加上补数,这样只留一个加法函数就可以了,同时也不必区分加数的正负,这很方便。
注意,我们直接用十进制补码就可以,因为补码方法是不区分进制的,而且我们是在编程环境中,所以硬件电路高低电平的误差限制不到我们,二进制没有必要。

步骤:

  1. 首先估算一下字长(要容纳三个数的和,至少需要的位数)。
    231-1是int能表示的最大值,21亿多,所以:
    3*231 > 63亿 > 50亿-1 = (1010 /2) - 1
    3*231 < 66亿 < 500亿-1 = (1011 /2) - 1
    因此字长N取11。
  2. 对于一个正数,我们直接把它对齐成11位即可;对于一个负数,将它的末位取10的补数,其余各位取9的补数。
  3. 加法函数采用最简单的串行进位的方式,设置一个carry当进位,按位相加再取模即可,只保留11位。
  4. 最后得到的结果是A+B-C的补码,只要最高位不超过4,同时不等于0,它就是一个正数,输出“true”。

使用long long类型的代码:
18ms,440KB

#include<iostream>
using namespace std;

int main()
{
    int T;
    cin >> T;
    for(int i=0; i<T; ++i) {
        long long A, B, C;
        cin >> A >> B >> C;
        if(A+B > C) {cout << "Case #" << i+1 << ": true" << endl;}
        else {cout << "Case #" << i+1 << ": false" << endl;}
    }
    return 0;
}

更快速的十进制补码加法代码:
6ms,456KB

#include <iostream>
#include <string>
#define N 11 //字长
using namespace std;

void ten_complement(string&, string&); //转换为补码
string add(string&, string&, string&); //加法函数

int main()
{
    int T;
    cin >> T;
    for(int i=0; i<T; ++i) {
        string A, B, C;
        string a(N,'0'), b(N,'0'), c(N,'0'), sum(N,'0');
        cin >> A >> B >> C;

        if(C[0] == '-') {C.erase(0, 1);} //使C变为相反数
        else {C.insert(0, 1, '-');}

        ten_complement(A, a);
        ten_complement(B, b);
        ten_complement(C, c);
        
        sum = add(a, b, c);
        string zero(N, '0');
        if(sum[0]<'5' && sum!=zero) { //和的最高位数字不能超过4,同时也不能是0
            cout << "Case #" << i+1 << ": true" << endl;
        }
        else {cout << "Case #" << i+1 << ": false" << endl;}
    }
    return 0;
}

void ten_complement(string& S, string& s)
{
    int l = S.size() - 1;
    for(int i=l, j=N-1; i>=0 && j>=0; --i, --j) {
        if(S[0] == '-') {
            if(i) { //末位取10的补数,其余位取9的补数
                s[j] = (i==l) + 9 + 2*'0' - S[i];
            }
            else {
                s[j] = 9 + '0';
                i = 1; //i到首位之后,停止后退
            }
        }
        else {s[j] = S[i];} //正数的补码即为本身
    }
}

string add(string& a, string& b, string& c)
{
    string sum(N, '0');
    char carry = '0';
    for(int i=N-1, x; i>=0; --i) {
        x = a[i] + b[i] + c[i] + carry - 4*'0';
        sum[i] = x % 10 + '0';
        carry = x / 10 + '0';
    }
    return sum;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值