题目描述
王老师正在教简单算术运算。细心的王老师收集了i道学生经常做错的口算题,并且想整理编写成一份练习。 编排这些题目是一件繁琐的事情,为此他想用计算机程序来提高工作效率。王老师希望尽量减少输入的工作量,比如 5+8 \texttt{5+8} 5+8 的算式最好只要输入 5 \texttt 5 5 和 8 \texttt 8 8,输出的结果要尽量详细以方便后期排版的使用,比如对于上述输入进行处理后输出 5+8=13 \texttt{5+8=13} 5+8=13 以及该算式的总长度 6 6 6。王老师把这个光荣的任务交给你,请你帮他编程实现以上功能。
输入格式
第一行为数值 i i i,接着的 i i i 行为需要输入的算式,每行可能有三个数据或两个数据。
若该行为三个数据则第一个数据表示运算类型, a \texttt a a 表示加法运算, b \texttt b b 表示减法运算, c \texttt c c 表示乘法运算,接着的两个数据表示参加运算的运算数。
若该行为两个数据,则表示本题的运算类型与上一题的运算类型相同,而这两个数据为运算数。
输出格式
输出 2 × i 2\times i 2×i 行。对于每个输入的算式,输出完整的运算式及结果,第二行输出该运算式的总长度
样例输入
4
a 64 46
275 125
c 11 99
b 46 64
样例输出
64+46=110
9
275+125=400
11
11*99=1089
10
46-64=-18
9
数据规模与约定
对于 50 % 50\% 50% 的数据,输入的算式都有三个数据,第一个算式一定有三个数据。
对于所有数据, 0 < i ≤ 50 0<i\leq 50 0<i≤50,运算数为非负整数且小于 10000 10000 10000。
思路分析
对于一个算式:a + b = c ,其中 a 和 b 是操作数,c是运算结果,+是运算符,=是等号。
算式a + b = c 的总长度等于a、b、c的长度加上2。
本题的难点在于, 1、当运算符和上一个相同时,就省略。这就造成每行第一次读取的不一定是操作符。
所以,需要对每行的第一次读入结果进行判断,是操作符还是整数。整数可能有多位,所以,第一次读入适合以字符串的方式读入。
重点要解决的问题:
1、对每行第一次读入字符串的判断,如果是操作符,保存;否则,将字符串转换成整数
2、算式长度的计算
学过字符串、ASCII码、循环、分支的同学,经过认真思考,可以写出下面的代码。
参考代码1
#include<iostream>
#include<string>
using namespace std;
char op;
string x;
//计算算式的长度:a的长度、b的长度、运算结果的长度和两个符号
int getlen(int a, int b, int c) {
int len = 0;
//累计a的长度
int t = a;
if (t == 0) len++; //如果a是0,占1位
while (t > 0) {
len++;
t /= 10;
}
//累计b的长度
t = b;
if (t == 0) len++; //如果b是0,占1位
while (t > 0) {
len++;
t /= 10;
}
//累计运算结果的长度
t = c;
if (t == 0) len++; //如果c是0,占1位
if (t < 0) {//如果c小于0,负号占一位
len++;
t = -t;
}
while (t > 0) {
len++;
t /= 10;
}
return len + 2; //总长度等于三个数字的长度加上运算符和等号
}
int main() {
int n;
cin >> n;
for (int i = 0; i < n; i++) {
int a = 0, b = 0; //每次都用新的变量
cin >> x;
//是操作符
if (x[0] == 'a' || x[0] == 'b' || x[0] == 'c') {
op = x[0];
cin >> a >> b;
} else {
//不是操作符,就把字符串x变成整数
for (int k = 0; k < x.size(); k++) {
int t = x[k] - '0'; //取出一个数字
a = a * 10 + t;
}
cin >> b;
}
//做运算
string s = "";
switch (op) {
case 'a': //+
cout << a << "+" << b << "=" << a + b << endl;
cout << getlen(a, b, a + b) << endl;
break;
case 'b': //+
cout << a << "-" << b << "=" << a - b << endl;
cout << getlen(a, b, a - b) << endl;
break;
case 'c': //+
cout << a << "*" << b << "=" << a*b << endl;
cout << getlen(a, b, a * b) << endl;
}//switch
}//for
return 0;
}
头文件cstdlib 中的atoi()函数可以将字符数组存放的整数转换成int类型。比如字符数组s中存储了三个数字字符’1’,‘2’,‘3’,char s[] = {'1','2','3','\0'};
, 那么 atoi(s) 就能得到整数123。
头文件cctype中的isalpha()函数可以判断一个字符是不是字母。比如,isalpha(‘a’)的结果是true,isalpha(‘3’)的结果是false。
学过函数atoi()和isalpha()的同学可以写出下方的代码:
参考代码2
#include<iostream>
#include<cstdlib>//atoi
#include<cctype> //isalpha,isdigit
using namespace std;
char op, x[1005];
int a, b, n;
//计算算式的长度
int getlen(int a, int b, int c) {
int len = 0;
//累计a的长度
int t = a;
if(t==0) len++; //0占1位
while (t > 0) {
len++;
t /= 10;
}
//累计b的长度
t = b;
if(t==0) len++;//0占1位
while (t > 0) {
len++;
t /= 10;
}
//累计运算结果的长度
t = c;
if(t==0) len++;//0占1位
if (t < 0) {//加上负号
len++;
t = -t;
}
while (t > 0) {
len++;
t /= 10;
}
return len + 2; //总长度等于三个数字的长度加上运算符和等号
}
int main() {
cin >> n;
for (int i = 0; i < n; i++) {
cin >> x;
//是操作符
if (isalpha(x[0])) {
op = x[0];
cin >> a >> b;
} else {
a = atoi(x); //不是操作符,就将s转换成整数
cin >> b;
}
//做运算
string s = "";
switch (op) {
case 'a': //+
cout << a << "+" << b << "=" << a + b << endl;
cout << getlen(a, b, a + b) << endl;
break;
case 'b': //+
cout << a << "-" << b << "=" << a - b << endl;
cout << getlen(a, b, a - b) << endl;
break;
case 'c': //+
cout << a << "*" << b << "=" << a*b << endl;
cout << getlen(a, b, a * b) << endl;
}//switch
}//for
return 0;
}
头文件cstdio中的sscanf和sprintf 和对字符数组进行输入输出。
sprintf()的返回值就是字符串的长度,直接保存下来就行了。
对这两个函数熟悉的同学可以写出下方的代码。
参考代码3:
#include <iostream> //cin & cout 用iostream
#include <cstring> //memset & strlen 用cstring
#include <cstdio> //sscanf & sprintf 用cstdio
using namespace std;
char s[100000010], x[10005]; //s-最终的等式,b-读入数据
int main() {
char op;//用于存储运算符
int n, a, b; //n-输入的算式数,a、b存储两个操作数
cin >> n;
for (int i = 0; i < n; i++) {
cin >> x; //读入,有可能是运算符,也有可能是数字
if (x[0] >= 'a' && x[0] <= 'z') {
op = x[0]; //如果是运算符就存入op,然后读入两个操作数
cin >> a >> b;
} else {
//不是运算符,就将字符串格式的整数转换成int
sscanf(x, "%d", &a);
cin >> b; //然后读入第二个整数
}
memset(s, 0, sizeof(s)); //每次使用前清空数组
int m; //用于保存算式的长度
switch (op) {
case 'a': //+
m=sprintf(s, "%d+%d=%d", a, b, a + b); //格式化运算式到字符数组
break;
case 'b': // -
m=sprintf(s, "%d-%d=%d", a, b, a - b); //格式化运算式到字符数组
break;
case 'c': //*
m=sprintf(s, "%d*%d=%d", a, b, a * b); //格式化运算式到字符数组
}
//输出完整的运算式和算式长度
cout << s << endl << m << endl;
}
return 0;
}
三种方法都可以解题。