声明
题解包含以下内容:
- (相对)高级的 C++ 模板及语法技巧
- 仅适用于 C++20 标准的代码
- 强烈的个人代码风格和 Modern C++ 范式追求
- 泛滥的标准库函数
换句话说就是(相较于其他公开题解)更低的查重率和更高的使用门槛;请酌情使用。
【id:119】【25分】A. 机器人变身(类与对象)
题目描述
编写一个机器人类,包含属性有机器名、血量、伤害值、防御值、类型和等级。其中血量、伤害和防御和等级、类型相关:
普通型机器人,类型为N,血量、伤害、防御是等级的5倍
攻击型机器人,类型为A,攻击是等级的10倍,其他属性和普通的一样
防御型机器人,类型为D,防御是等级的10倍,其他属性和普通的一样
生命型机器人,类型为H,生命是等级的50倍,其他属性和普通的一样。
机器人操作包括:打印、各个属性的获取和设置方法,构造函数可有可无,根据需要自行编写,
编写一个全局函数用于机器人变身,使得各种类型机器人能够相互转变。参数包括机器人对象指针和变身后的机器人类型,功能是修改机器人类型,并更改相关的属性。如果变身类型和机器人原来的类型不同,则执行变身功能,并返回true;如果变身类型和原来类型相同,则不执行变身,并返回false.
要求所有数据成员都是私有属性,用C++语言和面向对象设计思想来编程实现上述要求
输入
第一行输入t,表示要执行t次机器人变身
接着每两行,一行输入一个机器人的属性,包括机器名、类型、等级,机器名最大长度为20,另一行输入变身类型
依次类推输入
输出
每行输出变身后的机器人信息,要求调用机器人的打印方法来输出,即使机器人不变身也输出
属性输出依次为:名称、类型、等级、血量、伤害、防御
最后一行输出执行变身的次数
样例
输入样例1 | 输出样例1 |
---|---|
3 X001 N 5 H X002 A 5 D X003 D 5 D | X001–H–5–250–25–25 X002–D–5–25–25–50 X003–D–5–25–25–50 The number of robot transform is 2 |
Answer
#include <bits/stdc++.h>
using namespace std;
class Robot {
char type;
int level;
string name;
int health;
int damage;
int defence;
void update_attr() noexcept {
health = 5 * level;
damage = 5 * level;
defence = 5 * level;
if ( type == 'A' )
damage = 10 * level;
else if ( type == 'D' )
defence = 10 * level;
else if ( type == 'H' )
health = 50 * level;
}
public:
Robot( char tp, int lv, string nm )
: type { tp }, level { lv }, name { move( nm ) } {
update_attr();
}
Robot() : Robot( 'N', 0, "" ) {}
auto getType() const { return type; }
auto getLevel() const { return level; }
auto getName() const { return name; }
auto getHealth() const { return health; }
auto getDamage() const { return damage; }
auto getDefence() const { return defence; }
void print() {
cout << name << "--"
<< type << "--"
<< level << "--"
<< health << "--"
<< damage << "--"
<< defence << endl;
}
friend bool transformer( Robot* rbt, char tp ) {
if ( rbt->type == tp )
return false;
rbt->type = tp;
rbt->update_attr();
return true;
}
friend istream& operator>>( istream& is, Robot& rbt ) {
is >> rbt.name >> rbt.type >> rbt.level;
rbt.update_attr();
return is;
}
};
int main()
{
int t; cin >> t;
Robot rbt;
int cnt = 0;
while ( cin >> rbt ) {
char tp {}; cin >> tp;
if ( transformer( &rbt, tp ) )
++cnt;
rbt.print();
}
cout << "The number of robot transform is " << cnt << endl;
}
【id:120】【25分】B. 虚拟电话(构造与析构)
题目描述
虚拟电话包含属性:电话号、状态、机主姓名。
1、电话号是一个类,它包含号码和类型,其中号码是整数类型,类型用单个字母表示用户类别,A表示政府,B表示企业、C表示个人。类操作包括构造、属性的获取和设置等方法,根据需要自行编写。
2、状态用一个数字表示,1表示在用,0表示未用,
3、机主姓名是一个字符串
电话操作包括:构造、析构、打印和查询。
1、构造函数需要考虑复合类成员的构造,并且输出提示信息。假设电话号码为12345678,则构造函数输出"12345678 constructed."
2、打印是输出电话的相关信息,其中如果电话状态是在用则输出use;状态是未用则输出unuse,输出格式看示例。
3、析构函数是输出提示信息。假设电话号为12345678,则析构函数输出"12345678 destructed. "
4、查询操作是根据给定的号码查询电话,如果电话自身号码和给定号码不相同,则返回0;如果电话自身号码和给定号码相同,则返回1
用C++和面向对象思想实现以下要求:
1、输入相关数据,创建三个电话对象,并通过构造方法初始化。
2、输入若干个电话号码,通过查询操作查询这些号码是否在三个电话对象中,如果不存在输出"wrong number.",存在则调用打印操作输出电话信息,具体看输出样例。
输入
头三行输入三个电话信息,每行包括电话号码、电话类型、状态、机主姓名,机主姓名最大长度为20
接着一行输入t,表示有t个号码要查询
接着t行输入t个电话号码
输出
t行输出t个号码的查询结果
样例
输入样例1 | 输出样例1 |
---|---|
80000001 A 1 tom 80000002 B 0 ken 80000003 C 1 mary 3 50000002 80000003 80000002 | 80000001 constructed. 80000002 constructed. 80000003 constructed. wrong number. Phone=80000003–Type=C–State=use–Owner=mary Phone=80000002–Type=B–State=unuse–Owner=ken 80000003 destructed. 80000002 destructed. 80000001 destructed. |
Answer
#include <bits/stdc++.h>
using namespace std;
class PhoneNumber {
uint64_t phone_num;
char type;
public:
explicit PhoneNumber( uint64_t ph_n = 0, char tp = '\0' )
: phone_num { ph_n }, type { tp } {
}
auto getPhone() const { return phone_num; }
bool operator==( uint64_t ph_num ) const {
return phone_num == ph_num;
}
friend ostream& operator<<( ostream& os, const PhoneNumber& ph ) {
return os << "Phone=" << ph.phone_num << "--Type=" << ph.type;
}
};
class VirtualPhone {
PhoneNumber ph;
bool status;
string name;
public:
VirtualPhone( PhoneNumber ph, bool _status, string nm )
: ph { move( ph ) }, status { _status }, name { move( nm ) } {
cout << ph.getPhone() << " constructed.\n";
}
VirtualPhone( VirtualPhone&& rhs ) {
ph = move( rhs.ph );
status = rhs.status;
name = move( rhs.name );
}
~VirtualPhone() {
cout << ph.getPhone() << " destructed.\n";
}
bool query( uint64_t ph_num ) const {
return ph == ph_num;
}
friend ostream& operator<<( ostream& os, const VirtualPhone& vp ) {
return os << vp.ph << "--State="
<< (vp.status ? "use"sv : "unuse"sv) << "--Owner="
<< vp.name;
}
};
int main()
{
list<VirtualPhone> arr;
for ( size_t i = 0; i < 3; ++i ) {
size_t ph_num {}; char tp {};
int st {}; string nm {};
cin >> ph_num >> tp >> st >> nm;
arr.emplace_back( PhoneNumber( ph_num, tp ), st, move( nm ) );
}
size_t t {}; cin >> t;
while ( t-- ) {
uint64_t ph_num {}; cin >> ph_num;
if ( auto iter = find_if( arr.begin(), arr.end(),
[ph_num]( auto&& e ) -> bool { return e.query( ph_num ); } );
iter != arr.end() )
cout << *iter << endl;
else cout << "wrong number.\n";
}
while ( !arr.empty() ) // 维持析构顺序
arr.erase( prev( arr.end() ) );
}
【id:121】【25分】C. 银行账户(拷贝构造)
题目描述
银行账户包括余额、利率、号码、类型等属性,其中号是固定8位整数,类型表示个人还是企业账户,如果是个人用P标识,企业用E标识。
账户又分为活期账户和定期账户,活期利率为0.5%,定期利率为1.5%。
账户操作有计息、查询操作。计息操作是根据利率计算利息,并把利息增加到余额中,并做相关信息输出。查询操作是输出账户的全部信息。
创建一个活期账户,并通过构造函数初始化各个属性。然后通过拷贝构造来创建一个定期账户,信息与活期账户基本相同,不同之处包括:定期账户号码是活期账户号码加50000000(7个0);利率是定期利率。
要求所有数据成员都是私有属性
用C++语言的类与对象思想来编写程序实现上述要求
输入
输入测试个数t,表示有t个活期账户
先输入一个活期账户的账户号码、账户类型、余额(根据输入创建活期账户和定期账户)
接着输入两个操作符,第一个操作符对活期账户操作,第二个操作符对定期账户进行操作。若输入大写字母C表示计息操作,若输入大写字母P表示查询操作
以此类推输入其他账户的信息和操作
输出
每两行输出一对活期账户和定期账户的操作结果。
样例
输入样例1 | 输出样例1 |
---|---|
2 12345678 P 10000 C P 23456789 E 20000 P C | Account=12345678–sum=10050 Account=62345678–Person–sum=10000–rate=0.015 Account=23456789–Enterprise–sum=20000–rate=0.005 Account=73456789–sum=20300 |
Answer
#include <bits/stdc++.h>
using namespace std;
class BankAccount {
double balance;
int num;
char type;
double interest_rate;
public:
BankAccount( double balan, int id, char tp )
: balance { balan }, num { id }, type { tp } {
interest_rate = 0.005;
}
BankAccount() : BankAccount( 0, 0, '\0' ) {}
void change_to_fixed() {
num += 50000000;
interest_rate = 0.015;
}
void interest_accrual() {
balance += balance * interest_rate;
cout << "Account=" << num << "--sum=" << fixed << setprecision(0) << balance << endl;
}
void query() {
cout << "Account=" << num << "--" <<
(type == 'P' ? "Person" : "Enterprise") <<
"--sum=" << fixed << setprecision(0) << balance <<
"--rate=" << fixed << setprecision(3) << interest_rate << endl;
}
friend istream& operator>>( istream& is, BankAccount& lhs ) {
return is >> lhs.num >> lhs.type >> lhs.balance;
}
};
int main()
{
size_t t {}; cin >> t;
while ( t-- ) {
BankAccount current_acc;
cin >> current_acc;
BankAccount fixed_account = current_acc;
fixed_account.change_to_fixed();
char op1 {}, op2 {};
cin >> op1 >> op2;
if ( op1 == 'C' )
current_acc.interest_accrual();
else current_acc.query();
if ( op2 == 'C' )
fixed_account.interest_accrual();
else fixed_account.query();
}
}
【id:122】【25分】D. 电视遥控(静态+友元)【期中模拟】
题目描述
电视机包含音量、模式、频道号等属性,其中模式分为TV和DVD两种。电视机在TV模式下,将播放相应频道的内容;在DVD模式下,电视机使用统一的频道号播放DVD的内容,频道号统一为99。另外,电视机采用静态成员的方法共享两个数据:播放电视的电视机数量和播放DVD的电视机数量,初始都为0。
电视机操作包括打印、相关静态函数、属性的获取和设置等,根据需要自行编写。
现编写一个遥控器函数,通过友元方法对电视机进行控制,它的参数包括电视机对象、模式、变化音量、频道号,无返回值。函数操作包括:
1、对电视机对象进行模式设置,如果设置为DVD模式,则频道号参数一定是99;如果设置TV模式,则要把频道号设置相应的值。
2、根据变化音量进行调整,例如原有音量为50,现输入变化音量为-30,则50-30=20,音量最终为20。音量值最低为0,最高为100,超过范围则音量不再变化。
3、更新当前播放电视和播放DVD的电视机数量
4、调用电视机对象的打印方法输出电视相关信息
提示:如果电视机原来模式和参数传递的模式是相同的,那么实际操作就是调整音量、切换频道和输出信息。
注意:函数第一个参数必须是一个电视机对象,不可以是整数类型,可以是对象、或对象指针、或对象引用,根据需要自行编写。
用动态数组方法创建n台电视机,从1开始编号,频道号为编号,音量初始为50,模式为TV,然后通过遥控器函数对电视机进行控制。
所有类的数据成员都是私有属性。请使用C++语言和面向对象思想来实现上述要求
输入
第一行输入n,表示有n台电视台
第二行输入t,表示将执行t次遥控操作
接着输入t行,每行依次输入电视机编号i、模式k、频道号x和变化音量,其中i表示第i台电视机,k为1表示TV模式,k为2表示DVD模式。
输出
每行输出执行遥控操作后的电视机信息
最后一行输出当前播放电视和播放DVD的电视机数量。
具体格式看样例
样例
输入样例1 | 输出样例1 |
---|---|
10 5 3 1 11 20 4 2 99 -20 5 2 99 80 5 1 55 -60 6 2 99 -70 | 第3号电视机–TV模式–频道11–音量70 第4号电视机–DVD模式–频道99–音量30 第5号电视机–DVD模式–频道99–音量100 第5号电视机–TV模式–频道55–音量40 第6号电视机–DVD模式–频道99–音量0 播放电视的电视机数量为8 播放DVD的电视机数量为2 |
Answer
#include <bits/stdc++.h>
using namespace std;
#define TV 1
#define DVD 2
class Television {
static int tv_num;
static int dvd_num;
int mode;
int volume;
int channel_id;
int id;
public:
static int num_dvd() { return dvd_num; }
static int num_tv() { return tv_num; }
Television( int md = TV )
: mode { md }, volume { 50 } {
channel_id = id = dvd_num + tv_num + 1;
mode == DVD ? ++dvd_num : ++tv_num;
}
~Television() {
mode == DVD ? --dvd_num : --tv_num;
}
Television& adjust_vol( int variation ) {
auto tmp = volume + variation;
volume = tmp > 100 ? 100 : tmp < 0 ? 0 : tmp;
return *this;
}
Television& set_mode( int md, int channel = 0 ) {
if ( md == DVD ) {
channel_id = 99;
if ( mode != DVD ) {
++dvd_num;
--tv_num;
}
}
else {
channel_id = channel;
if ( mode != TV ) {
--dvd_num;
++tv_num;
}
}
mode = md;
return *this;
}
friend ostream& operator<<( ostream& os, const Television& tv ) {
return os << "第" << tv.id << "号电视机--"
<< (tv.mode == DVD ? "DVD" : "TV") << "模式--频道"
<< tv.channel_id << "--音量" << tv.volume;
}
friend void controller( Television& );
};
int Television::tv_num = 0;
int Television::dvd_num = 0;
void controller( Television& tv ) {
int md {}, ch_id {}, vol {};
cin >> md >> ch_id >> vol;
tv.set_mode( md, ch_id ).adjust_vol( vol );
cout << tv << endl;
}
int main()
{
size_t n {}; cin >> n;
auto arr = new Television[n] {};
size_t t {}; cin >> t;
while ( t-- ) {
size_t offset {}; cin >> offset;
controller( arr[offset - 1] );
}
cout << "播放电视的电视机数量为" << Television::num_tv() << endl
<< "播放DVD的电视机数量为" << Television::num_dvd() << endl;
}