声明
题解包含以下内容:
- (相对)高级的 C++ 模板及语法技巧
- 仅适用于 C++20 标准的代码
- 强烈的个人代码风格和 Modern C++ 范式追求
- 泛滥的标准库函数
换句话说就是(相较于其他公开题解)更低的查重率和更高的使用门槛;请酌情使用。
【id:27】【20分】A. 对象数组(类和对象)
题目描述
课堂上我们谈到类这个概念,比如第一题我们有学生类这个抽象的概念,成千上万个学生都具有同样的属性,但针对某个具体学生来说,他/她具有自己的鲜明个性,比如计算机专业的王海同学,信息工程学院的李慧同学,那么我们是定义一个该类的变量:Student student; 假设该类包含姓名、学号、性别、所属学院、联系电话等;在程序运行过程,把变量student赋予不同值就可以让它表示是王海还是李慧,尝试定义一个学生数组(比如四个元素大小,请思考此时四个对象是如何初始化的呢?),然后输入四个不同学生各项属性给数组里学生初始化(最好定义一个输入函数),然后输出该学生对象数组的各对象的姓名。
输入
输入数组元素的大小
依次每行输入每个对象的各项属性值,各属性值最大长度不超过30
输出
每行输出一个学生类对象的姓名
样例
输入样例1 | 输出样例1 |
---|---|
3 tom 2013333333 男 计算机学院 13766666666 Marry 2012222222 女 信息工程学院 13555555555 John 2014444444 男 管理学院 13888888888 | tom Marry John |
Answer
#include <bits/stdc++.h>
#define OJSTRUCT Student
using namespace std;
class OJSTRUCT {
public:
string name;
string id;
string sex;
string collage;
string phone;
friend istream& operator>>(istream& is, OJSTRUCT& lhs) {
return is >> lhs.name >> lhs.id >> lhs.sex >> lhs.collage >> lhs.phone;
}
};
int main()
{
int n; cin >> n;
auto arr = new OJSTRUCT[n];
for (int i = 0; i < n; i++)
cin >> arr[i];
for_each(arr, arr + n,
[](auto&& stu) -> void {
cout << stu.name << endl;
});
delete[] arr;
}
【id:162】【20分】B. 身体评估(类与对象)
题目描述
评估成年人身体健康有多个指标,包括BMI、体脂率等
设计一个身体健康类,包含私有成员:姓名、身高(米)、体重(公斤),腰围(厘米),实现两个公有方法如下:
BMI方法,返回BMI数值(整数,四舍五入到个位),计算公式BMI= 体重 / 身高的平方
体脂率方法,返回体脂率数值(浮点数),计算过程如下:
1)参数a=腰围(cm)×0.74
2)参数b=体重(kg)×0.082+34.89
3)体脂肪重量(kg)=a-b
4)体脂率 = 体脂肪重量÷体重
其它方法根据需要自行定义
输入
第一行输入t表示有t个测试实例
第二行起,每行输入四个参数:姓名、身高、体重、腰围,姓名的最大长度不超过20
依次输入t行
输出
输出t行,每行输出一个实例的BMI和体脂率,BMI四舍五入到个位,体脂率小数数值精确到小数点后2位
在C++中,输出指定精度的参考代码如下:
#include <iostream>
#include <iomanip> //必须包含这个头文件
using namespace std;
void main( )
{
double a =3.14;
cout<<fixed<<setprecision(2)<<a<<endl; //输出小数点后2位
}
样例
输入样例1 | 输出样例1 |
---|---|
2 张高 1.85 78.5 85.2 李圆 1.55 67.6 77.3 | 张高的BMI指数为23–体脂率为0.28 李圆的BMI指数为28–体脂率为0.25 |
Answer
#include <bits/stdc++.h>
#define OJSTRUCT Person
using namespace std;
class OJSTRUCT {
string name;
double tall;
double waistline;
double weight;
public:
string get_name() const { return name; }
double fat_rate() const {
return ((waistline * 0.74) - (weight * 0.082 + 34.89)) / weight;
}
int BMI() const {
return static_cast<int>(round(weight / (tall * tall)));
}
friend istream& operator>>(istream& is, OJSTRUCT& lhs) {
return is >> lhs.name >> lhs.tall >> lhs.weight >> lhs.waistline;
}
};
int main()
{
int t; cin >> t;
auto vec = vector<OJSTRUCT>(t);
for (auto& stu : vec)
cin >> stu;
for_each(vec.begin(), vec.end(),
[](auto&& p) -> void {
cout << p.get_name() << "的BMI指数为" << p.BMI()
<< "--体脂率为" << fixed << setprecision(2)
<< p.fat_rate() << endl;
});
}
【id:160】【20分】C. 最胖的加菲(类与对象+数组)
题目描述
有一群猫猫,每只猫都有自己的名称和体重。
用类来描述猫,名称和体重都是私有属性,要求加入属性的get方法。其他函数根据需要自己定义
创建一个动态的猫对象数组,存储各只猫的名称和体重
根据猫的体重对数组做升序排序,并输出排序后每只猫的名称
题目涉及的数值均用整数处理
输入
第一行输入n表示有n只猫
第二行输入一只猫的名称和体重,名称的最大长度为30
依次输入n行
输出
输出一行,输出排序后的猫的名称
样例
输入样例1 | 输出样例1 |
---|---|
4 巧克力胖三斤 1500 自来水瘦八两 400 芝士蛋糕肥六斤 3000 蔬菜沙拉轻四两 200 | 蔬菜沙拉轻四两 自来水瘦八两 巧克力胖三斤 芝士蛋糕肥六斤 |
Answer
#include <bits/stdc++.h>
#define OJSTRUCT Cat
using namespace std;
class OJSTRUCT {
string name;
int weight;
public:
string get_name() const { return name; }
int get_weight() const { return weight; }
auto operator<=>(const OJSTRUCT& lhs) const {
return weight <=> lhs.weight;
}
friend istream& operator>>(istream& is, OJSTRUCT& lhs) {
return is >> lhs.name >> lhs.weight;
}
};
int main()
{
int t; cin >> t;
auto vec = vector<OJSTRUCT>(t);
for (auto& cat : vec)
cin >> cat;
sort(vec.begin(), vec.end(), less<OJSTRUCT>());
for_each(vec.begin(), vec.end(),
[](auto&& p) -> void {
cout << p.get_name() << ' ' ;
});
cout << endl;
}
【id:30】【20分】D. 点和圆 (类与对象)
题目描述
设计一个点类Point,包含属性:x坐标和y坐标,方法:设定坐标(setPoint),获取x坐标(getX),获取y坐标(getY)
设计一个圆类Circle,包含属性:圆心坐标x和y、半径r;方法包括:
- 设定圆心(setCenter),设置圆心x坐标和y坐标
- 设定半径(setRadius),设置半径长度
- 计算面积(getArea),计算公式:面积=3.14rr
- 计算周长(getLength),计算公式:周长=23.14r
- 包含(contain),判断一个圆是否包含一个点,计算圆心到这个点的距离,然后和半径做比较,大于则不包含,小于等于则包含
注意:提交代码时必须用注释划分出三个区域:类定义、类实现、主函数,如下
//-----类定义------
class XXX
{
// 写类定义代码
};
//----类实现------
void XXX::process()
{
// 写类定义代码
};
//-----主函数-----
int main()
{
//自定义一些变量
//创建一个圆对象和一个点对象
//输入圆对象和点对象的属性数值,并做初始化
//输出圆的面积和圆的周长
//输出圆是否包含点,包含则输出yes,否则输出no
return 0;
}
输入
第一行输入圆的三个整数参数:圆心的x和y坐标,半径
第二行输入点的两个整数参数:x和y坐标
输出
第一行输出圆的面积和周长,结果之间用空格隔开,输出精度到小数点后2位
第二行输出圆是否包含点,包含则输出yes,否则输出no
在C++中,输出指定精度的参考代码如下:
#include <iostream>
#include <iomanip> //必须包含这个头文件
using namespace std;
void main( )
{
double a =3.14;
cout<<fixed<<setprecision(3)<<a<<endl; //输出小数点后3位
}
样例
输入样例1 | 输出样例1 |
---|---|
1 1 1 2 2 | 3.14 6.28 no |
提示
求两点距离的公式 dis =sqrt [ (x1-x2)^2 + (y1-y2)^2 ] , ^2表示平方,sqrt表示开平方根,本公式只是表示含义,不是真实代码
在C++使用sqrt函数可以求平方根,头文件包含cmath
Answer
#include <bits/stdc++.h>
using namespace std;
class Point {
double x, y;
public:
Point() : x {}, y {} {}
void setPoint(double xx, double yy) noexcept {
x = xx; y = yy;
}
void setPoint(const Point& lhs) noexcept {
x = lhs.x; y = lhs.y;
}
double getX() const noexcept { return x; }
double getY() const noexcept { return y; }
double operator-(const Point& lhs) const {
const auto new_x = x - lhs.x;
const auto new_y = y - lhs.y;
return sqrt(pow(new_x, 2) + pow(new_y, 2));
}
friend istream& operator>>(istream& is, Point& lhs) {
return is >> lhs.x >> lhs.y;
}
};
class Circle {
Point center;
double radius;
public:
Circle() : radius {} {}
void setRadius(double _radius) noexcept { radius = _radius; }
void setCenter(Point _center) noexcept { center = move(_center); }
double getArea() const noexcept { return 3.14 * pow(radius, 2); }
double getLength() const noexcept { return 2 * 3.14 * radius; }
bool contain(const Point& p) const { return p - center <= radius; }
friend istream& operator>>(istream& is, Circle& lhs) {
return is >> lhs.center >> lhs.radius;
}
};
int main()
{
Circle c; cin >> c;
Point pt; cin >> pt;
cout << fixed << setprecision(2)
<< c.getArea() << ' ' << c.getLength() << endl
<< (c.contain(pt) ? "yes" : "no") << endl;
}
【id:156】【20分】E. 存折类定义(类与对象)
题目描述
定义一个存折类CAccount,存折类具有帐号(account, long)、姓名(name,char[10])、余额(balance,float)等数据成员,可以实现存款(deposit,操作成功提示“saving ok!”)、取款(withdraw,操作成功提示“withdraw ok!”)和查询余额(check)的操作,取款金额必须在余额范围内,否则提示“sorry! over limit!”。编写主函数,建立这个类的对象并测试,输入账号、姓名、余额后,按照查询余额、存款、查询余额、取款、查询余额的顺序调用类方法并输出。
输入
第一个存折的账号、姓名、余额
存款金额
取款金额
第二个存折的账号、姓名、余额
存款金额
取款金额
输出
第一个存折的账户余额
存款操作结果
账户余额
取款操作结果
账户余额
第二个存折的账户余额
存款操作结果
账户余额
取款操作结果
账户余额
样例
输入样例1 | 输出样例1 |
---|---|
9111 Tom 1000 500 1000 92220 John 500 500 1500 | Tom’s balance is 1000 saving ok! Tom’s balance is 1500 withdraw ok! Tom’s balance is 500 John’s balance is 500 saving ok! John’s balance is 1000 sorry! over limit! John’s balance is 1000 |
Answer
#include <bits/stdc++.h>
using namespace std;
class CAccount {
long account;
float balance;
char name[11];
public:
CAccount() {
memset(this, 0, sizeof(CAccount));
}
string_view deposit(float num) {
balance += num;
return "saving ok!"sv;
}
string_view withdraw(float num) {
if (num > balance)
return "sorry! over limit!"sv;
balance -= num;
return "withdraw ok!"sv;
}
float check() const noexcept {
return balance;
}
string_view get_name() const noexcept {
return name;
}
friend istream& operator>>(istream& is, CAccount& lhs) {
string buffer;
is >> lhs.account >> buffer >> lhs.balance;
strncpy(lhs.name, buffer.c_str(), 10);
return is;
}
friend ostream& operator<<(ostream& os, const CAccount& lhs) {
os << lhs.get_name() << "'s balance is "sv << lhs.check();
return os;
}
};
int main()
{
CAccount account;
while (cin >> account) {
cout << account << endl;
// 存款
float num {}; cin >> num;
cout << account.deposit(num) << endl
<< account << endl;;
cin >> num; // 取款
cout << account.withdraw(num) << endl
<< account << endl;
}
}