声明
题解包含以下内容:
- (相对)高级的 C++ 模板及语法技巧
- 仅适用于 C++20 标准的代码
- 强烈的个人代码风格和 Modern C++ 范式追求
- 泛滥的标准库函数
换句话说就是(相较于其他公开题解)更低的查重率和更高的使用门槛;请酌情使用。
【id:81】【20分】A. 三维坐标点的平移(运算符重载)
题目描述
定义一个三维点Point类,利用友元函数重载"++“和”–"运算符,并区分这两种运算符的前置和后置运算。
要求如下:
- 实现Point类;
- 编写main函数,初始化1个Point对象,将这个对象++或–后赋给另外一个对象,并输出计算后对象的坐标信息。
输入
第1行:输入三个int类型的值,分别为一个Point对象p1的x,y,z坐标。
输出
第1行:Point对象p1后置++之后的坐标信息输出。
第2行:Point对象p1后置++操作后赋给另外一个Point对象p2的坐标信息。
第3行开始,依次输出前置++,后置–,前置–运算的坐标信息,输出格式与后置++一样。
即:
p2=p1++;
第1行输出p1
第2行输出p2
p1恢复原值
p2=++p1;
第3行输出p1
第4行输出p2
p1恢复原值
p2=p1–;
第5行输出p1
第6行输出p2
p1恢复原值
p2=–p1;
第7行输出p1
第8行输出p2
样例
输入样例1 | 输出样例1 |
---|---|
10 20 30 | x=11 y=21 z=31 x=10 y=20 z=30 x=11 y=21 z=31 x=11 y=21 z=31 x=9 y=19 z=29 x=10 y=20 z=30 x=9 y=19 z=29 x=9 y=19 z=29 |
提示
原值是最初输入的数值
第1行是p1后置++后,再输出
第2行是p1恢复原值,接着p1后置++同时复制给p2,p2输出
第3、4行是p1恢复原值,p1前置++同时输出,然后p1再输出
第5、6行是p1恢复原值,p1后置–后,再输出,接着输出一次原值
第7、8行是p1恢复原值,p1前置–同时输出,然后p1再输出
Answer
#include<bits/stdc++.h>
using namespace std;
class Point {
int x, y, z;
public:
constexpr Point( int xx = 0, int yy = 0, int zz = 0 ) noexcept
: x { xx }, y { yy }, z { zz } {}
friend constexpr Point operator++( Point& p ) noexcept {
++p.x; ++p.y; ++p.z;
return p;
}
friend constexpr Point operator++( Point& p, int ) noexcept {
Point tmp = p;
++p.x; ++p.y; ++p.z;
return tmp;
}
friend constexpr Point operator--( Point & p ) noexcept {
--p.x; --p.y; --p.z;
return p;
}
friend constexpr Point operator--( Point &p, int ) noexcept {
Point tmp = p;
--p.x; --p.y; --p.z;
return tmp;
}
void show() const {
cout << "x=" << x << " y=" << y << " z=" << z << endl;
}
friend istream& operator>>( istream& is, Point& p ) {
return is >> p.x >> p.y >> p.z;
}
};
int main()
{
Point p1, p2;
cin >> p1;
const Point p1_bk = p1;
p1++; p1.show();
(p2 = (p1 = p1_bk)++).show();
(++(p1 = p1_bk)).show();
(p2 = ++(p1 = p1_bk)).show();
(p1 = p1_bk)--; p1.show();
(p2 = (p1 = p1_bk)--).show();
(--(p1 = p1_bk)).show();
(p2 = --(p1 = p1_bk)).show();
}
不会出题就别几把出,这什么破题?话都说不明白。
还有正常人会用友元重载自增运算符?垃圾题目真给你烂完了。
【id:191】【20分】B. 货币加减(运算符重载)
题目描述
定义CMoney类,包含元、角、分三个数据成员,友元函数重载‘+’、‘-’,实现货币的加减运算(假设a-b中a的金额始终大于等于b的金额),
重载输入及输出,实现货币的输入,输出。
读入最初的货币值,对其不断进行加、减操作,输出结果。
可根据需要,为CMoney类添加构造函数或其它成员函数。
输入
测试次数
每组测试数据格式如下:
第一行,初始货币:元 角 分
第二行开始,每行一个操作:add 元 角 分(加)、minus 元 角 分(减)、stop(结束)
输出
对每组测试数据,输出操作终止后的货币金额,具体输出格式见样例。
样例
输入样例1 | 输出样例1 |
---|---|
2 0 0 0 add 48 9 0 minus 0 5 3 add 18 6 8 add 12 1 2 stop 10 2 5 add 5 8 0 add 32 1 2 minus 10 5 9 minus 37 5 8 stop | 79元1角7分 0元0角0分 |
Answer
#include <bits/stdc++.h>
using namespace std;
class CMoney {
int yuan, jiao, fen;
public:
explicit CMoney( int y = 0, int j = 0, int f = 0 )
: yuan { y }, jiao { j }, fen { f } {}
friend CMoney operator+( const CMoney& a, const CMoney& b ) {
const auto tmp = (a.fen + a.jiao * 10 + a.yuan * 100) + (b.fen + b.jiao * 10 + b.yuan * 100);
return CMoney( tmp / 100, tmp / 10 % 10, tmp % 10 );
}
friend CMoney operator-( const CMoney& a, const CMoney& b ) {
const auto tmp = (a.fen + a.jiao * 10 + a.yuan * 100) - (b.fen + b.jiao * 10 + b.yuan * 100);
return CMoney( tmp / 100, tmp / 10 % 10, tmp % 10 );
}
friend istream& operator>>( istream& is, CMoney& m ) {
return is >> m.yuan >> m.jiao >> m.fen;
}
friend ostream& operator<<( ostream& os, const CMoney& m ) {
return os << m.yuan << "元" << m.jiao << "角" << m.fen << "分";
}
};
int main()
{
#ifdef _WIN32
system( "chcp 65001" );
#endif
size_t t {}; cin >> t;
while ( t-- ) {
CMoney cash; cin >> cash;
string order;
while ( (cin >> order) && order != "stop" ) {
if ( order == "add" ) {
CMoney add; cin >> add;
cash = cash + add;
} else if ( order == "minus" ) {
CMoney sub; cin >> sub;
cash = cash - sub;
}
}
cout << cash << endl;
}
}
【id:93】【20分】C. 时钟调整(运算符前后增量)
题目描述
假定一个时钟包含时、分、秒三个属性,取值范围分别为0~11,0~59,0~59,具体要求如下:
1、用一元运算符++,并且是前增量的方法,实现时钟的调快操作。例如要把时钟调快5秒,则执行5次” ++<对象> “ 的操作
2、用一元运算符–,并且是后增量的方法,实现时钟的调慢操作。例如要把时钟调慢10秒,则执行10次” <对象>-- “的操作
3、用构造函数的方法实现时钟对象的初始化,用输出函数实现时钟信息的输出
clock和time是系统内部函数,所以不要用来做类名或者其他
输入
第一行输入时钟的当前时间时、分、秒
第二行输入t表示有t个示例
第三行输入t个整数x,如果x为正整数,则表示执行调快操作,使用重载运算符++;如果x为负整数,则表示执行调慢操作,使用重载运算符–
每次的调快或调慢操作都是承接上一次调整后的结果进行,例如先调快10秒,再调慢2秒,那么调慢2秒是接着调快10秒后的结果进行的
输出
每行输出每个时钟调整操作后的时分秒
样例
输入样例1 | 输出样例1 |
---|---|
11 58 46 4 5 70 -22 -55 | 11:58:51 0:0:1 11:59:39 11:58:44 |
Answer
#include <bits/stdc++.h>
using namespace std;
class Clock {
int hour, minute, second;
public:
Clock( int hh, int mm, int ss )
: hour { hh }, minute { mm }, second { ss } {}
Clock() : Clock( {}, {}, {} ) {}
Clock& operator++() noexcept {
++second;
if ( second == 60 ) {
second = 0;
++minute;
if ( minute == 60 ) {
minute = 0;
++hour;
}
}
hour %= 12;
return *this;
}
Clock operator--( int ) noexcept {
Clock before = *this;
--second;
if ( second == -1 ) {
second = 59;
--minute;
if ( minute == -1 ) {
minute = 59;
--hour;
}
}
hour = hour == -1 ? 11 : hour;
return before;
}
friend istream& operator>>( istream& is, Clock& ck ) {
return is >> ck.hour >> ck.minute >> ck.second;
}
friend ostream& operator<<( ostream& os, const Clock& ck ) {
return os << ck.hour << ":" << ck.minute << ":" << ck.second;
}
};
int main()
{
Clock ck; cin >> ck;
size_t t; cin >> t;
while ( t-- ) {
int x; cin >> x;
if ( x > 0 )
while ( x-- )
++ck;
else while ( x++ )
ck--;
cout << ck << endl;
}
}
【id:190】【20分】D. X的放大与缩小(运算符重载)
题目描述
X字母可以放大和缩小,变为n行X(n=1,3,5,7,9,…,21)。例如,3行x图案如下:
现假设一个n行(n>0,奇数)X图案,遥控器可以控制X图案的放大与缩小。遥控器有5个按键,1)show,显示当前X图案;2)show++, 显示当前X图案,再放大图案,n+2;3)++show,先放大图案,n+2,再显示图案;4)show–,显示当前X图案,再缩小图案,n-2;5)–show,先缩小图案,n-2,再显示图案。假设X图案的放大和缩小在1-21之间。n=1时,缩小不起作用,n=21时,放大不起作用。
用类CXGraph表示X图案及其放大、缩小、显示。主函数模拟遥控器,代码如下,不可修改。请补充CXGraph类的定义和实现。
int main()
{
int t, n;
string command;
cin >> n;
CXGraph xGraph(n);
cin >> t;
while (t--)
{
cin >> command;
if (command == "show++")
{
cout << xGraph++ << endl;
}
else if(command == "++show")
{
cout << ++xGraph << endl;
}
else if (command == "show--")
{
cout << xGraph-- << endl;
}
else if (command == "--show")
{
cout << --xGraph << endl;
}
else if (command == "show")
{
cout << xGraph << endl;
}
}
return 0;
}
输入
第一行n,大于0的奇数,X图案的初始大小。
第二行,操作次数
每个操作一行,为show、show++、show–、–show、++show之一,具体操作含义见题目。
输出
对每个操作,输出对应的X图案。
样例
输入样例1 | 输出样例1 |
---|---|
3 5 show show++ show++ ++show --show | XXX X XXX XXX X XXX XXXXX XXX X XXX XXXXX XXXXXXXXX XXXXXXX XXXXX XXX X XXX XXXXX XXXXXXX XXXXXXXXX XXXXXXX XXXXX XXX X XXX XXXXX XXXXXXX |
Markdown 用的 HTML 标签不能和带文本编辑的 OJ 相比,将就着看就行,也不是不能用。
Answer
#include <bits/stdc++.h>
using namespace std;
class CXGraph {
int n;
public:
CXGraph( int nn )
: n { nn } {}
CXGraph& operator++() noexcept {
if ( n < 21 )
n += 2;
return *this;
}
CXGraph operator++( int ) noexcept {
CXGraph before = *this;
this->operator++();
return before;
}
CXGraph& operator--() noexcept {
if ( n > 1 )
n -= 2;
return *this;
}
CXGraph operator--( int ) noexcept {
CXGraph before = *this;
this->operator--();
return before;
}
friend ostream& operator<<( ostream& os, const CXGraph& g ) {
string output;
for ( int i = 0; i < g.n; i += 2 )
output.append( i / 2, ' ' ).append( g.n - i, 'X' ).push_back( '\n' );
for ( int i = g.n - 3; i >= 0; i -= 2 )
output.append( i / 2, ' ' ).append( g.n - i, 'X' ).push_back( '\n' );
return os << output;
}
};
int main()
{
int t, n;
string command;
cin >> n;
CXGraph xGraph( n );
cin >> t;
while ( t-- ) {
cin >> command;
if ( command == "show++" ) {
cout << xGraph++ << endl;
} else if ( command == "++show" ) {
cout << ++xGraph << endl;
} else if ( command == "show--" ) {
cout << xGraph-- << endl;
} else if ( command == "--show" ) {
cout << --xGraph << endl;
} else if ( command == "show" ) {
cout << xGraph << endl;
}
}
return 0;
}
【id:188】【20分】E. 矩形关系(运算符重载)
题目描述
假设坐标采用二维平面坐标。
定义点类CPoint,包含属性x,y(整型)。方法有:带参构造函数,getX,getY分别返回点的x坐标,y坐标。
定义矩形类CRectangle,包含属性:矩形的左上角坐标leftPoint,右下角坐标rightPoint。类中方法有:
1)带参构造函数,初始化矩形的左上角、右下角
2)重载>运算符,参数为CPoint点对象,假设为p,若p在矩形内,返回true,否则返回false。
3)重载>运算符,第一个矩形若包含第二个矩形(部分边界可以相等),返回true,否则返回false。(要求该函数调用2)实现)
4)重载==运算符,判断两个矩形是否一致,返回true或false。
5)重载*运算符,判断两个矩形是否有重叠部分,返回true或false。
6)重载类型转换运算符,计算矩形的面积并返回,面积是整型。
7)重载<<运算符,输出矩形的两个角坐标,具体格式见样例。
输入2个矩形,计算面积,判断矩形的关系。主函数如下,不可修改。
int main()
{
int t, x1, x2, y1, y2;
cin >> t;
while (t--)
{
// 矩形1的左上角、右下角
cin >> x1 >> y1 >> x2 >> y2;
CRectangle rect1(x1, y1, x2, y2);
// 矩形2的左上角、右下角
cin >> x1 >> y1 >> x2 >> y2;
CRectangle rect2(x1, y1, x2, y2);
// 输出矩形1的坐标及面积
cout << "矩形1:" << rect1 << " " << (int)rect1 << endl;
// 输出矩形2的坐标及面积
cout << "矩形2:" << rect2 << " " << (int)rect2 << endl;
if (rect1 == rect2)
{
cout << "矩形1和矩形2相等" << endl;
}
else if (rect2 > rect1)
{
cout << "矩形2包含矩形1" << endl;
}
else if (rect1 > rect2)
{
cout << "矩形1包含矩形2" << endl;
}
else if (rect1 * rect2)
{
cout << "矩形1和矩形2相交" << endl;
}
else
{
cout << "矩形1和矩形2不相交" << endl;
}
cout << endl;
}
return 0;
}
可根据需要,添加构造函数和析构函数。
输入
测试次数
每组测试数据如下:
矩形1的左上角、右下角坐标
矩形2的左上角、右下角坐标
输出
每组测试数据输出如下,中间以空行分隔:
矩形1的坐标和面积(具体格式见样例)
矩形2的坐标和面积(具体格式见样例)
矩形1和矩形2的关系(矩形1包含矩形2、矩形2包含矩形1、矩形2和矩形1相等、矩形1和矩形2相交、矩形1和矩形2不相交)
样例
输入样例1 | 输出样例1 |
---|---|
2 1 4 4 1 2 3 3 2 1 4 4 1 0 3 5 2 | 矩形1:1 4 4 1 9 矩形2:2 3 3 2 1 矩形1包含矩形2 矩形1:1 4 4 1 9 矩形2:0 3 5 2 5 矩形1和矩形2相交 |
Answer
#include <bits/stdc++.h>
using namespace std;
class CPoint {
int x, y;
public:
CPoint( int xx, int yy )
: x { xx }, y { yy } {}
CPoint() : CPoint( {}, {} ) {}
int getX() const noexcept { return x; }
int getY() const noexcept { return y; }
bool operator==( const CPoint& p ) const noexcept {
return x == p.x && y == p.y;
}
friend ostream& operator<<( ostream& os, const CPoint& point ) {
return os << point.x << " " << point.y;
}
};
class CRectangle {
CPoint leftPoint, rightPoint;
public:
CRectangle( CPoint left, CPoint right )
: leftPoint { move( left ) }, rightPoint { move( right ) } {}
CRectangle( int xx1, int yy1, int xx2, int yy2 ) : CRectangle( { xx1, yy1 }, { xx2, yy2 } ) {}
bool operator>( const CPoint& p ) const noexcept {
return
leftPoint.getX() <= p.getX() && p.getX() <= rightPoint.getX() &&
rightPoint.getY() <= p.getY() && p.getY() <= leftPoint.getY();
}
bool operator>( const CRectangle& r ) const noexcept {
return operator>( r.leftPoint ) && operator>( r.rightPoint );
}
bool operator==( const CRectangle& r ) const noexcept {
return r.leftPoint == leftPoint && r.rightPoint == rightPoint;
}
bool operator*( const CRectangle& r ) const noexcept {
return
rightPoint.getX() >= r.leftPoint.getX() && // this 的右下点要在 r 的左上点的右方
rightPoint.getY() <= r.leftPoint.getY() && // this 的右下点要在 r 的左上点的下方
r.rightPoint.getX() >= leftPoint.getX() && // this 的左上点要在 r 的右下点的左方
r.rightPoint.getY() <= leftPoint.getY(); // this 的左上点要在 r 的右下点的上方
}
operator int() const noexcept {
return abs( leftPoint.getX() - rightPoint.getX() ) * abs( leftPoint.getY() - rightPoint.getY() );
}
friend ostream& operator<<( ostream& os, const CRectangle& r ) {
return os << r.leftPoint << " " << r.rightPoint;
}
};
int main()
{
#ifdef _WIN32
system( "chcp 65001" );
#endif
int t, x1, x2, y1, y2;
cin >> t;
while ( t-- ) {
// 矩形1的左上角、右下角
cin >> x1 >> y1 >> x2 >> y2;
CRectangle rect1( x1, y1, x2, y2 );
// 矩形2的左上角、右下角
cin >> x1 >> y1 >> x2 >> y2;
CRectangle rect2( x1, y1, x2, y2 );
// 输出矩形1的坐标及面积
cout << "矩形1:" << rect1 << " " << (int)rect1 << endl;
// 输出矩形2的坐标及面积
cout << "矩形2:" << rect2 << " " << (int)rect2 << endl;
if ( rect1 == rect2 ) {
cout << "矩形1和矩形2相等" << endl;
} else if ( rect2 > rect1 ) {
cout << "矩形2包含矩形1" << endl;
} else if ( rect1 > rect2 ) {
cout << "矩形1包含矩形2" << endl;
} else if ( rect1 * rect2 ) {
cout << "矩形1和矩形2相交" << endl;
} else {
cout << "矩形1和矩形2不相交" << endl;
}
cout << endl;
}
return 0;
}