信阳师范大学2024年C++练习题
**
XYOJ欢迎访问http://xyoj.xynu.edu.cn/ranklist.php练习系统链接
**
问题 A: 递归函数分段求和
题目描述
请设计一个递归分段求和函数Sum(int Start, int End)用于计算Start至End间的整数的和,当Start<End时计算Sum= Start + (Start + 1) + ……+ (End - 1) + End;当Start=End时则返回Start;当Start>End时则返回0。
输入格式
输入包含多组测试数据,每组测试数据包含两个整数Start与End。
输出格式
输出每组测试数据的计算结果,每组测试数据的计算结果占一行。
输入样例
20 30
56 50
5 5
输出样例
275
0
5
数据范围与提示
请严格按照 样例输入 和 样例输出 的格式来编写程序的输入和输出,不需要额外增加诸如“请输入…”等辅助性提示。
关于多组数据输入,请参照如下网页中的代码 http://xyoj.xynu.edu.cn/viewnews.php?id=1005
参考答案
#include<iostream>
using namespace std;
int sum(int start ,int end){
if(start<end){
return start+sum(start+1,end);
}else if (start ==end){
return start;
}else{
return 0;
}
}
int main(){
int start, end;
while (cin >> start >> end) {
cout << sum(start,end) << endl;
}
return 0;
}
问题 B: 求n阶勒让德多项式的值
题目描述
用递归的方法编写函数求n阶勒让德多项式的值,在主程序中实现输入输出。递归公式为
P(n, x) = {
1 (n = 0);
x (n = 1);
[(2n - 1)x * p(n - 1, x) - (n - 1) * p(n - 2, x)] / n (n >1);
}
输入格式
输入包含一系列的n和x对,通过空格隔开。一对n和x占一行。
输出格式
对于输入的每对n和x,你需要依次输出P(x),如果n为0,直接输出1,如果n为1,直接输出x。
如对于输入中的第二对n和x,在输出中它们的商应该也在第二行。
输入样例
2 6
1 25
0 3
输出样例
53.5
25
1
数据范围与提示
请读懂输入和输出样例中的格式要求,然后编写对应输入和输出的程序。
参考答案
#include<iostream>
using namespace std;
float P(int n, int x) {
if (n == 0) {
return 1;
}
if (n == 1) {
return x;
}
else {
return ((2 * n - 1) * x * P(n - 1, x) - (n - 1) * P(n - 2, x)) / n;
}
}
int main() {
int n, x;
while (cin >> n >> x) {
cout << P(n, x) << endl;
}
return 0;
}
问题 C: 编写递归与重载函数getPower计算x的y次方
题目描述
编写递归函数getPower计算x的y次方,在同一个程序中针对整型和实型实现两个重载的函数:
int getPower(int x, int y); //整型版本,当y < 0时,返回0
double getPower(double x, int y); //实型版本
在主程序中实现输入输出,分别输入一个整数a和一个双精度浮点数b作为底数,再输入一个整数m作为指数,输出a的m次方和b的m次方。
为确保重载函数能执行,题目于2023.03.21日完善,将输入中的第二个数由整数调整为浮点数。
输入格式
输入包含多组数据,其中每组数据是一行输入,包含 a(int类型)、b(double类型) 和 m(int类型) ,由空格间隔。
输出格式
对于输入的每对a、b和m,你需要依次输出a的m次方和b的m次方,二者各占一行。
输入样例
2 5.1 5
2 1.8 4
输出样例
32
3450.25
16
10.4976
数据范围与提示
请使用递归函数实现,并分别设计两个函数名称相同但形式参数不同的函数实现函数重载
参考答案
#include<iostream>
#include<cmath>
using namespace std;
int getPower(int x, int y) {
if (y >= 0) {
return pow(x, y);
}
}
float getPower(float x, int y) {
if (y >= 0) {
return pow(x, y);
}
}
int main() {
int a, m;
float b;
while (cin >> a >> b >> m) {
cout << getPower(a, m) << endl;
cout << getPower(b, m) << endl;
}
return 0;
}
问题 D: 面向对象之时针类的设计与实现
题目描述
请设计一个时针类 Clock 并使用它。
其有私有 int 类型的数据成员Hour, Minute, Second;
有公有成员函数SetTime(int newHour, int newMinute, int newSecond) 用以设置时针新时间;
有ShowTime()用以在控制台输出时间;
有构造函数Clock(),用以设置时针类对象创建时的默认时间00:00:00,并输出文字信息作为提示;
有析构函数~Clock(),用以释放时针类创建的对象,并输出对象释放的文字信息作为提示。
输入格式
程序通过输入字符来控制程序的输入与输出操作。
输入字符’m’时则意味着要设置时针的时间,此时请分别输入时 分 秒数值并以空格间隔,然后调用设置时间的函数
输入字符’s’时则输出Clock类的对象存储的时间,此时调用输出时间函数
输入字符’e’时则要退出程序(退出程序时,系统会自动释放类的对象并自动调用析构函数,不需要显式调用析构函数)。
输出格式
程序首先输出一行文字 “The instance of class Clock is created”,然后根据用户输入’m’、's’或’e’进行对应的输出操作。
输入样例
m
8 20 30
m
10 25 36
s
e
输出样例
The instance of class Clock is created
The new time value 8:20:30 is setted
The new time value 10:25:36 is setted
Time is 10:25:36
The instance of class Clock is destroied
数据范围与提示
请严格根据输入样例和输出样例控制程序结构并根据输入给出正确输出,
为确保大家了解构造函数和析构函数的功能与意义,请分别在各个函数中编写信息输出代码(正常情况下,输出提示信息不应放在类的成员函数中实现,但此处只是为了促进大家对这些函数的了解与掌握)。
所有的输入都应在主函数中实现,输出语句应在类的函数中实现,具体如下:
输出语句“The instance of class Clock is created”应在类的构造函数中实现,
输出语句“The instance of class Clock is destroied”应在类的析构函数中实现,
输出语句“The new time value XXXXXX is setted”应在类的SetTime函数中实现,
输出语句“Time is XXXXXX ”应在类的ShowTime函数中实现,
程序通过输入字符的判断代码(m, s, e)应在主函数中,根据判断结果调用类对象的相关方法。
OJ环境下Linux C++),请不要使用clock, time, ctime, mtime 作为类名称,因为它们是系统函数,若使用将触发编译错误。
建议以Ctime作为类名称。
参考答案
#include <iostream>
using namespace std;
class Clock {
private:
int Hour;
int Minute;
int Second;
public:
Clock() {
Hour = 0;
Minute = 0;
Second = 0;
cout << "The instance of class Clock is created" << endl;
}
void SetTime(int newHour, int newMinute, int newSecond) {
Hour = newHour;
Minute = newMinute;
Second = newSecond;
cout << "The new time value " << Hour << ":" << Minute << ":" << Second << " is setted" << endl;
}
void ShowTime() {
cout << "Time is " << Hour << ":" << Minute << ":" << Second << endl;
}
~Clock() {
cout << "The instance of class Clock is destroied" << endl;
}
};
int main() {
Clock clock;
char input;
int hour, minute, second;
while (true) {
cin >> input;
if (input == 'm') {
cin >> hour >> minute >> second;
clock.SetTime(hour, minute, second);
} else if (input == 's') {
clock.ShowTime();
} else if (input == 'e') {
break;
}
}
return 0;
}
问题 E: 定义一个复数类 Complex,并根据要求答题
题目描述
定义一个复数类 Complex,使得下面的代码可以能够工作:
Complex c1(3, 5); //用复数 3+5i 初始化 c1
Complex c2 = 4.5; //用实数 4.5 初始化 c2
c1.add(c2); //将c1与c2相加,结果保存在c1中
c1.show(); //将c1输出(这时的结果应该是7.5+5i)
输入格式
输入包含两行数据,
第一行是c1的实部和虚部的数值
第二行是c2的实部
输出格式
输出包含五行数据
第一行对应输入第一行的反馈结果,如“正在构建类的实例,其实部为3,虚部为5”
第二行对应输入第二行的反馈结果,如“正在调用复制构造函数,实部为4.5,虚部为0”
第三行对应代码第三行的反馈结果,如“正在调用add函数”
第四行对应代码第四行的反馈结果,如“正在调用show函数”
第五行对应代码第四行的反馈结果,如“7.5+5i”
输入样例
3 5
4.5
输出样例
正在构建类的实例,其实部为3,虚部为5
正在调用复制构造函数,实部为4.5,虚部为0
正在调用add函数
正在调用show函数
7.5+5i
数据范围与提示
1.请考虑现实中复数情况确定实部和虚部的数据类型
2.请注意复制构造函数的用法及扩展
3.“正在构建类的实例,其实部为3,虚部为5”,此句提示的源代码应放在构造函数中;“正在调用复制构建函数,实部为4.5,虚部为0”,此句提示的源代码应放在复制构造函数中;“正在调用add函数”,此句提示的源代码应放在add函数中;“正在调用show函数”,此句提示的源代码应放在show函数中。
参考答案
#include <iostream>
using namespace std;
class Complex {
private:
double real;
double imag;
public:
// 构造函数
Complex(double r, double i) : real(r), imag(i) {
cout << "正在构建类的实例,其实部为" << real << ",虚部为" << imag << endl;
}
// 复制构造函数
Complex(double r) : real(r), imag(0) {
cout << "正在调用复制构建函数,实部为" << real << ",虚部为" << imag << endl;
}
// 加法操作
void add(const Complex& c) {
real += c.real;
imag += c.imag;
cout << "正在调用add函数" << endl;
}
// 输出操作
void show() const {
cout << "正在调用show函数" << endl;
cout << real << "+" << imag << "i" << endl;
}
};
int main() {
double r1, i1;
double r2;
cin >> r1 >> i1;
cin >> r2;
Complex c1(r1, i1);
Complex c2 = r2;
c1.add(c2);
c1.show();
return 0;
}
问题 F: 三维空间中点的定义与操作(类的定义与实现)
题目描述
三维空间通常采用(X,Y,Z)坐标表示一个点,点有移动(移动至一个新坐标点)、坐标值增减计算(以当前坐标为基准,分别增加若干个单位至一个新坐标)和输出点坐标的3个操作(即3个成员函数);为确保数据安全,用户不能直接对点的坐标赋值(X,Y,Z坐标均为整数),点之间有计算距离(double类型)的操作。
请你设计一个类Point与类的一个外部友元函数PointDis(Point &A, Point &B),实现上述功能。
输入格式
输入数据包含3行,第一行是点的初始坐标,第二行是点移动后的新坐标,第三行分别是对坐标X轴,Y轴和Z轴的增加量。
输出格式
输出数据包含4行,
第一行是“点的坐标为:(X,Y,Z)”,对应输入数据的第一行的输出;
第二行是“移动后点的坐标为:(X,Y,Z)”,对应输入数据的第二行的输出;
第三行是“移动的距离为:XXX”,对应输入数据的第二行的输出;
第四行是“X轴、Y轴和Z轴增量后点的坐标为:(X,Y,Z)”,对应输入数据的第三行的输出;。
输入样例
10 20 30
-10 20 30
-10 20 30
输出样例
点的坐标为:(10,20,30)
移动后点的坐标为:(-10,20,30)
移动的距离为:20
X轴、Y轴和Z轴增量后点的坐标为:(-20,40,60)
数据范围与提示
请确保输出字符中的“(”和“,”是中文标点符号,并确保输出格式与样例一致。
平方根函数为sqrt,幂函数为pow,它们的头文件为
参考答案
#include<iostream>
#include<cmath>
using namespace std;
class Point {
public:
int x, y, z;
Point(int X, int Y, int Z) : x(X), y(Y), z(Z) {}
void move(int X, int Y, int Z) {
x = X, y = Y, z = Z;
}
void increase(int X, int Y, int Z) {
x += X, y += Y, z += Z;
}
void print() const {
cout << "点的坐标为:(" << x << "," << y << "," << z << ")" << endl;
}
void print2() const {
cout << "X轴、Y轴和Z轴增量后点的坐标为:(" << x << "," << y << "," << z << ")" << endl;
}
friend double PointDis(Point& A, Point& B);
};
double PointDis(Point& A, Point& B) {
return sqrt(pow(A.x - B.x, 2) + pow(A.y - B.y, 2) + pow(A.z - B.z, 2));
}
int main() {
int x, y, z;
int x1, y1, z1;
cin >> x >> y >> z;
Point P(x, y, z);
P.print();
cin >> x1 >> y1 >> z1;
Point Q(x1, y1, z1);
double dist = PointDis(P, Q);
cout << "移动后点的坐标为:(" << Q.x << "," << Q.y << "," << Q.z << ")" << endl;
cout << "移动的距离为:" << dist << endl;
P.move(x1, y1, z1);
cin >> x >> y >> z;
P.increase(x, y, z);
P.print2();
return 0;
}
问题 G: 静态成员、静态函数与友元函数的用法
题目描述
定义一个Cat类,其拥有静态数据成员numOfCats,记录已经创建的Cat对象的个体数目,静态数据成员numOfCatsGo,记录已经销毁的Cat对象的个体数目;静态成员函数getNumOfCats(bool IsConstruted),当IsConstruted为true时读取numOfCats,当IsConstruted为false时读取numOfCatsGo;数据私有成员weight,记录Cat对象的体重。
定义一个Boat类,其拥有数据私有成员weight,记录Boat对象的体重。
根据上述请完成如下内容:
(1)请设计一个Cat类,体会静态数据成员和静态成员函数的用法。
(2)定义一个Cat类和Boat类的友元函数getTotalWeight(),计算一个Cat对象和Boat对象的体重和并返回。
输入格式
第一行输入正整数N,表示即将创建Cat类对象的个数,
第二行输入浮点数W0,表示一个Cat对象的体重
第三行输入浮点是W1,表示一个Boat对象的体重。
输出格式
首先先输出2N行数据,分别表示当前Cat对象创建时已经创建的对象个数,已经在内存中存在的对象个数;当前Cat对象销毁时,Cat对象在内存中存在的对象个数。(对应N个对象)
再输出1行表示Cat对象创建时已经创建的对象个数,已经在内存中存在的对象个数。(新创建一个对象,用于后续体重和计算)
然后输出一个Cat对象与一个Boat对象的体重和。
最后输出Cat对象销毁时,Cat对象在内存中存在的对象个数。
输入样例
3
60.1
80.1
输出样例
Cat Object is constructing, the constructed Number is 1, and the living Number is 1
Cat Object is deconstructing, and the living Number is 0
Cat Object is constructing, the constructed Number is 2, and the living Number is 1
Cat Object is deconstructing, and the living Number is 0
Cat Object is constructing, the constructed Number is 3, and the living Number is 1
Cat Object is deconstructing, and the living Number is 0
Cat Object is constructing, the constructed Number is 4, and the living Number is 1
140.2
Cat Object is deconstructing, and the living Number is 0
数据范围与提示
请注意使用构造函数和析构函数计算静态变量和输出与 constructing, deconstructing 相关字符串
请注意样例输出中的相关格式信息。
参考答案
#include <iostream> // 包含输入输出流头文件
using namespace std;
class Boat; // 前向声明 Boat 类
class Cat {
private:
float weight; // 猫的体重
static int numOfCats; // 静态成员,记录猫的总数
static int numOfCatsGo; // 静态成员,记录离开的猫的总数
public:
// 构造函数,初始化体重,并增加猫的总数
Cat(float w) : weight(w) {
numOfCats++;
cout << "Cat Object is constructing, the constructed Number is " << numOfCats << ", and the living Number is " << numOfCats - numOfCatsGo << std::endl;
}
// 析构函数,增加离开的猫的总数
~Cat() {
numOfCatsGo++;
cout << "Cat Object is deconstructing, and the living Number is " << numOfCats - numOfCatsGo << std::endl;
}
// 静态成员函数,返回猫的总数或离开的猫的总数
static int getNumOfCats(bool isConstructed) {
return isConstructed ? numOfCats : numOfCatsGo;
}
// 友元函数声明,允许 getTotalWeight 访问 Cat 类的私有成员
friend float getTotalWeight(const Cat &cat, const Boat &boat);
};
int Cat::numOfCats = 0; // 初始化静态成员 numOfCats
int Cat::numOfCatsGo = 0; // 初始化静态成员 numOfCatsGo
class Boat {
private:
float weight; // 船的体重
public:
// 构造函数,初始化体重
Boat(float w) : weight(w) {}
// 友元函数声明,允许 getTotalWeight 访问 Boat 类的私有成员
friend float getTotalWeight(const Cat &cat, const Boat &boat);
};
// 友元函数定义,返回猫和船的总体重
float getTotalWeight(const Cat &cat, const Boat &boat) {
return cat.weight + boat.weight;
}
int main() {
int N; // 猫的数量
float W0, W1; // 猫和船的体重
// 输入猫的数量和猫、船的体重
cin >> N;
cin >> W0;
cin >> W1;
// 创建并删除 N 只猫对象
for (int i = 0; i < N; ++i) {
Cat *cat = new Cat(W0);
delete cat;
}
Cat *lastCat = new Cat(W0); // 创建最后一只猫对象
Boat boat(W1); // 创建船对象
cout << getTotalWeight(*lastCat, boat) << std::endl; // 输出最后一只猫和船的总重量
delete lastCat; // 删除最后一只猫对象
return 0; // 返回 0,程序结束
}
问题 H: 编写函数 void Reverse(string & Str),用递归算法使字符串Str倒序。
题目描述
编写一个如下声明的递归函数,使得字符串Str倒序,并在主程序中调用该函数测试效果
函数声明:void Reverse(string & Str);
输入格式
输入为连续多行的多个字符串,一个字符串一行,每个字符串由阿拉伯数字、字母或特殊字符组成,字符串中不包括空格。
输出格式
输出为输入倒序后的字符串,一行输出一个字符串,对应于一行输入字符串的倒序字符串。
输入样例
4adasdfczxcv
asdfzxcvwertqwe
输出样例
vcxzcfdsada4
ewqtrewvcxzfdsa
数据范围与提示
请使用C++中的std::string类实现.
参考答案
#include <iostream>
#include<cstring>
using namespace std;
void re (char* s ){
int len = strlen(s);
if (len == 1 )
{
cout << *s;
}
else
{
re(s + 1);
cout << *s ;
}
}
int main() {
char s[100];
while ( cin >> s ) {
re (s);
cout << endl;
}
return 0;
}
问题 I: 点的定义与操作
题目描述
二维空间通常采用X,Y坐标表示一个点,点有移动、坐标值增减计算(如分别增加若干个单位)和输出点坐标的3个操作;为确保数据安全,用户不能直接对点的X,Y坐标赋值(X,Y坐标均为整数),请你设计一个类,实现上述功能。
输入格式
输入数据包含3行,第一行是点的初始坐标,第二行是点移动后的新坐标,第三行分别是对坐标X轴和Y轴的增加量。
输出格式
输入数据包含3行,第一行是“点的坐标为:(X,Y)”,第二行是“移动后点的坐标为:(X,Y)”,第三行是“X轴和Y轴增量后点的坐标为:(X,Y)”。
输入样例
5 5
5 10
25 3
输出样例
点的坐标为:(5,5)
移动后点的坐标为:(5,10)
X轴和Y轴增量后点的坐标为:(30,13)
数据范围与提示
请确保输出字符中的中文标点符号并确保程序输出格式与样例一致。
参考答案
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
int x, y;
int x1, y1;
int a, b;
double juli;
cin >> x >> y;
cin >> x1 >> y1;
cin >> a >> b;
juli = sqrt(pow(x - x1, 2) + pow(y - y1, 2));
cout << "点的坐标为:(" << x << "," << y << ")" << endl;
cout << "移动后点的坐标为:(" << x1 << "," << y1 << ")" << endl;
cout << "X轴和Y轴增量后点的坐标为:(" << x1 + a << "," << y1 + b << ")" << endl;
return 0;
}
问题 J: 类继承与多态
题目描述
请设计一个圆的类,该类继承于第2题(OJ:4326)设计的类(可根据需要修改第2题的类以满足题目要求)并实现如下功能,增加一个半径的数据成员,并分别设计设置半径的成员函数(如圆的半径为XX.XX)与计算周长的成员函数(如圆的周长为XX.XX)(10分);根据多态性,在第2题点移动的基础上设计一个圆移动的成员函数,输出移动后的圆心坐标(如圆移动后的圆心坐标为:XXX,YYY)(15分);对加法运算符重载,其计算规则为:新圆圆心为两个圆心的平均值,半径为两个圆半径之和,返回值为计算结果对应的对象(25分)。
输入格式
输入数据包含4行,第一行是圆心的初始坐标,第二行是圆半径值,第三行圆心的新坐标,第四行是另一个圆的圆心坐标和半径值。
输出格式
输出数据包含8行,第一行是“圆的初始圆心坐标为:(X,Y)”,第二行是“圆的半径为:XX.YY”,第三行是“圆的周长为:XX.YY”,第四行是“圆移动后的圆心坐标为:(X,Y)”,第五行是“圆的初始圆心坐标为:(X,Y)”,第六行是“圆的半径为:XX.YY”,第七行与第八行是加法的运算结果,第七行是“圆的初始圆心坐标为:(X,Y)”,第八行是“圆的半径为:XX.YY”。坐标为整数,半径和周长保留2位小数。
输入样例
23 32
5.1
50 60
61 71 2.2
输出样例
圆的初始圆心坐标为:(23,32)
圆的半径为:5.10
圆的周长为:32.04
圆移动后的圆心坐标为:(50,60)
圆的初始圆心坐标为:(61,71)
圆的半径为:2.20
圆的初始圆心坐标为:(55,65)
圆的半径为:7.30
数据范围与提示
请确保输出字符中的中文标点符号并确保程序输出格式与样例一致。
如使用 cout<<fixed << setprecision(2)<<输出变量 控制输出精度,请添加如下头文件:#include
PI 取 3.1415926,请使用float类型表示半径和周长。
参考答案
#include <iostream>
#include <iomanip>
using namespace std;
class Point {
public:
int x, y;
Point(int x = 0, int y = 0) : x(x), y(y) {}
};
class Circle {
public:
Point center;
float radius;
Circle(Point c = Point(), float r = 0) : center(c), radius(r) {}
void setRadius(float r) {
radius = r;
}
float getPerimeter() {
return 2 * 3.1415926 * radius;
}
void move(Point newCenter) {
center = newCenter;
}
Circle operator+(const Circle &c) {
Point newCenter((center.x + c.center.x) / 2, (center.y + c.center.y) / 2);
float newRadius = radius + c.radius;
return Circle(newCenter, newRadius);
}
};
int main() {
int x1, y1, x2, y2, x3, y3;
float r1, r2;
cin >> x1 >> y1 >> r1;
Point p1(x1, y1);
Circle c1(p1, r1);
cin >> x2 >> y2;
Point p2(x2, y2);
c1.move(p2);
cin >> x3 >> y3 >> r2;
Point p3(x3, y3);
Circle c2(p3, r2);
cout << "圆的初始圆心坐标为:(" << p1.x << "," << p1.y << ")" << endl;
cout << "圆的半径为:" << fixed << setprecision(2) << c1.radius << endl;
cout << "圆的周长为:" << fixed << setprecision(2) << c1.getPerimeter() << endl;
cout << "圆移动后的圆心坐标为:(" << p2.x << "," << p2.y << ")" << endl;
cout << "圆的初始圆心坐标为:(" << p3.x << "," << p3.y << ")" << endl;
cout << "圆的半径为:" << fixed << setprecision(2) << c2.radius << endl;
Circle c3 = c1 + c2;
cout << "圆的初始圆心坐标为:(" << c3.center.x << "," << c3.center.y << ")" << endl;
cout << "圆的半径为:" << fixed << setprecision(2) << c3.radius << endl;
return 0;
}
问题 K: 捕食者的游戏,请使用类的继承与多态实现相关代码
题目描述
一个虚基类 Animal,它具有所有动物的共同特征,包括Name(名字)、Height(身高)、Weight(体重)、Speed(速度)以及Trophic-Level(营养级)。
继承Animal的Herbivore类,是表示草食性动物的类,
继承Animal的Carnivore类,是表示肉食性动物的类,
继承Animal的Human类,是表示人的类,
继承Carnivore的三个类:Small Carnivore(小型食肉动物)、Medium Carnivore(中型食肉动物)和 Large Carnivore(大型食肉动物)。
在模拟食物链规则中,捕食规则如下:
1.捕食总是发生在相邻的两个动物之间(相邻关系由初次输入次序确定而不再发生改变),如没有相邻动物则该动物自动存活。
2.肉食性动物能够捕食草食性动物,只要肉食性动物的速度高于草食性动物的速度。
3.大型食肉动物可以捕食小型食肉动物,只要遵循同样的速度规则。
4.中型食肉动物捕食小型食肉动物时,或大型食肉动物捕食中型食肉动物时,除速度外,还需要在身高和体重上都超过对方。
程序运行时,首先输入动物总数,然后顺序输入每个动物的各项属性。在模拟捕食过程中,动物会依次相互比较,如果满足捕食条件,则会发生捕食行为。捕食成功后,参与的这两个动物都将不再参与后续捕食行为以模拟它们已经完成捕食或已成为其他动物的食物。值得注意的是,一旦有人类存在,则所有动物都不会被吃掉,因为人类会保护动物。
输入格式
为方便,使用"H"表示Herbivore类的一个实例,同理,"R"表示Human,"SC"表示Small Carnivore,"MC"表示Medium Carnivore和"LC"表示Large Carnivore。
输入格式:第一行输入一个整数n,表示所有动物的总数。然后输入n行,每行依次输入类型Type(H、LC、MC、SC、R),名字Name,身高Height,体重Weight,速度Speed。
输出格式
程序输出存活的每种动物类型及其存活个数,每行表示一种动物类型名字、数量及其对应的存活实例名字。
输出格式:第一行输出:Remaining animals:”随后是若干存活动物的行,每行输出依旧存活的动物类型与总个数,然后输出对应的名字。
输入样例
8
LC bear 20 45 17
H rabbit 15 25 40
H rabbit2 23 34 45
MC wolf 23 45 67
LC bear2 15 46 70
LC tiger 15 25 12
SC bird 15 25 32
SC cat 15 25 62
输出样例
Remaining animals:
Herbivore (1): rabbit
Small Carnivore (2): bird, cat
Medium Carnivore (1): wolf
Large Carnivore (3): bear, bear2, tiger
参考答案
#include <bits/stdc++.h>
using namespace std;
const int GRASS = 1;
const int SMALL_CARNIVORE = 2;
const int MEDIUM_CARNIVORE = 3;
const int LARGE_CARNIVORE = 4;
const int HUMAN = 5;
struct AnimalType {
int count;
string names;
};
class Animal {
protected:
double H;
double We;
double spd;
public:
Animal(string n, double h, double w, double s, int tl)
: name(n), H(h), We(w), spd(s), trophicLevel(tl) {}
virtual bool canPredate(Animal& other) = 0;
virtual ~Animal() {}
double getHeight() const { return H; }
double getWeight() const { return We; }
double getSpeed() const { return spd; }
string getName() const { return name; }
int trophicLevel;
string name;
};
class Herbivore : public Animal {
public:
Herbivore(string name, double h, double w, double s)
: Animal(name, h, w, s, GRASS) {}
bool canPredate(Animal& other) override {
return false;
}
};
class Carnivore : public Animal {
public:
Carnivore(string name, double h, double w, double s, int tl)
: Animal(name, h, w, s, tl) {}
bool canPredate(Animal& other) override {
if (other.trophicLevel == GRASS && this->spd > other.getSpeed()) {
return true;
}
else if (this->trophicLevel > other.trophicLevel + 1 &&
this->spd > other.getSpeed()) {
return true;
}
else if (this->trophicLevel > other.trophicLevel &&
this->H > other.getHeight() &&
this->We > other.getWeight() &&
this->spd > other.getSpeed()) {
return true;
}
else
return false;
}
};
class LargeCarnivore : public Carnivore {
public:
LargeCarnivore(string name, double h, double w, double s)
: Carnivore(name, h, w, s, LARGE_CARNIVORE) {}
};
class MediumCarnivore : public Carnivore {
public:
MediumCarnivore(string name, double h, double w, double s)
: Carnivore(name, h, w, s, MEDIUM_CARNIVORE) {}
};
class SmallCarnivore : public Carnivore {
public:
SmallCarnivore(string name, double h, double w, double s)
: Carnivore(name, h, w, s, SMALL_CARNIVORE) {}
};
class Human : public Animal {
public:
Human(string name, double h, double w, double s)
: Animal(name, h, w, s, HUMAN) {}
bool canPredate(Animal& other) override {
return false;
}
};
int main() {
int numAnimals;
cin >> numAnimals;
vector<Animal*> animals;
for (int i = 0; i < numAnimals; ++i) {
string type;
string name;
double H, We, spd;
cin >> type >> name >> H >> We >> spd;
if (type == "R") {
animals.push_back(new Human(name, H, We, spd));
}
else if (type == "H") {
animals.push_back(new Herbivore(name, H, We, spd));
}
else if (type == "SC") {
animals.push_back(new SmallCarnivore(name, H, We, spd));
}
else if (type == "MC") {
animals.push_back(new MediumCarnivore(name, H, We, spd));
}
else if (type == "LC") {
animals.push_back(new LargeCarnivore(name, H, We, spd));
}
}
vector<AnimalType> res(5);
for (auto& t : res) {
t.count = 0;
t.names = "";
}
bool hasHuman = false;
for (Animal* animal : animals) {
if (animal->trophicLevel == HUMAN) {
hasHuman = true;
break;
}
}
if (!hasHuman) {
for (size_t i = 0; i < animals.size() - 1; i++) {
if (animals[i]->canPredate(*animals[i + 1])) {
animals.erase(animals.begin() + i + 1);
}
else if (animals[i + 1]->canPredate(*animals[i])) {
animals.erase(animals.begin() + i);
}
}
}
for (Animal* animal : animals) {
int index = animal->trophicLevel - 1;
res[index].count++;
if (!res[index].names.empty()) {
res[index].names += ", ";
}
res[index].names += animal->name;
}
map<int, string> type_names = { {1, "Herbivore"},
{2, "Small Carnivore"},
{3, "Medium Carnivore"},
{4, "Large Carnivore"},
{5, "Human"} };
cout << "Remaining animals:" << endl;
for (int i = 0; i < res.size(); ++i) {
if (res[i].count > 0) {
cout << type_names[i + 1] << " (" << res[i].count << "): " << res[i].names
<< endl;
}
}
for (Animal* animal : animals) {
delete animal;
}
return 0;
}