add fourth homework

This commit is contained in:
gameloader 2022-10-29 16:17:36 +08:00
parent c8ebc260f5
commit b9fdd44cc1

View File

@ -39,7 +39,7 @@ author = "Logic"
{{< figure src="https://gcore.jsdelivr.net/gh/game-loader/picbase@master/uPic/1004TxWH43.png" >}} {{< figure src="https://gcore.jsdelivr.net/gh/game-loader/picbase@master/uPic/1004TxWH43.png" >}}
2. **声明一个dog类包含体重合年龄两个成员变量及相应的成员两数声明一个实例dog1.体重为5年龄为10使用I/O流把dog1的状态写入磁盘文件再声明另一个实例dog2通过读文件把dog1的状态赋给dog2。分别使用文本方式和二进制方式操作文件看看有何不同再看看磁盘文件的ASCI码有何不同。** 1. **声明一个dog类包含体重合年龄两个成员变量及相应的成员两数声明一个实例dog1.体重为5年龄为10使用I/O流把dog1的状态写入磁盘文件再声明另一个实例dog2通过读文件把dog1的状态赋给dog2。分别使用文本方式和二进制方式操作文件看看有何不同再看看磁盘文件的ASCI码有何不同。**
这个题只是在第一个题的基础上结合面向对象编程,简单的声明一个类并构造两个成员函数,一个用于修改对象的信息,一个用于打印对象的信息。在打开文件流的时候用两种不同的方式打开文件流即可。 这个题只是在第一个题的基础上结合面向对象编程,简单的声明一个类并构造两个成员函数,一个用于修改对象的信息,一个用于打印对象的信息。在打开文件流的时候用两种不同的方式打开文件流即可。
@ -118,7 +118,7 @@ int main() {
这里并没有显示出什么差异主要是因为对于可见字符来说使用二进制方式和文本方式差异不大但是对于一些不可见字符如文件的文件头等二进制读取方式会将数据原封不动的读取出来而文本则会处理为文本后读取因为txt文件除了编码类型外无文件头所以二者没什么区别但对于其他有格式文件来说可能就会存在区别另外以文本方式打开时遇到结束符CTRLZ(0x1A)就认为文件已经结束。所以,若使用文本方式打开二进制文件,就很容易出现文件读不完整,或內容不对的错误。即使是用文本方式打开文本文件,也要谨慎使用,比如复制文件,就不应该使用文本方式。 这里并没有显示出什么差异主要是因为对于可见字符来说使用二进制方式和文本方式差异不大但是对于一些不可见字符如文件的文件头等二进制读取方式会将数据原封不动的读取出来而文本则会处理为文本后读取因为txt文件除了编码类型外无文件头所以二者没什么区别但对于其他有格式文件来说可能就会存在区别另外以文本方式打开时遇到结束符CTRLZ(0x1A)就认为文件已经结束。所以,若使用文本方式打开二进制文件,就很容易出现文件读不完整,或內容不对的错误。即使是用文本方式打开文本文件,也要谨慎使用,比如复制文件,就不应该使用文本方式。
3. **编写程序提示用户输入一个十进制整数.分别用十进制、八进制、和十六进制形式输出。** 1. **编写程序提示用户输入一个十进制整数.分别用十进制、八进制、和十六进制形式输出。**
对进制进行转换可以使用短除反取余的方式除对应进制数然后反向取余数即可。但是如果用int 或者long int类型存储输入的十进制数并进行转换能转换的数字大小是有限的在考虑可能有大整数的情况下使用字符串存储并进行大整数的模数运算从而实现了大整数的进制转换。该程序可以输入任意大的整数都可以完成进制转换。 对进制进行转换可以使用短除反取余的方式除对应进制数然后反向取余数即可。但是如果用int 或者long int类型存储输入的十进制数并进行转换能转换的数字大小是有限的在考虑可能有大整数的情况下使用字符串存储并进行大整数的模数运算从而实现了大整数的进制转换。该程序可以输入任意大的整数都可以完成进制转换。
@ -245,7 +245,7 @@ int main(int argc, char *argv[]) {
{{< figure src="https://gcore.jsdelivr.net/gh/game-loader/picbase@master/uPic/1011Jy1fbS.png" >}} {{< figure src="https://gcore.jsdelivr.net/gh/game-loader/picbase@master/uPic/1011Jy1fbS.png" >}}
4. **编写程序实现如下功能:打开指定的一个文木文件,在每一个行前加行号。** 1. **编写程序实现如下功能:打开指定的一个文木文件,在每一个行前加行号。**
本题考察C++基本的文件IO和文件指针比较方便的做法是用一个中间文件首先读取原文件的内容每读取一行加一个行号并写入到中间文件中最后将加了行号的中间文件内容再写入原文件并删除中间文件。 本题考察C++基本的文件IO和文件指针比较方便的做法是用一个中间文件首先读取原文件的内容每读取一行加一个行号并写入到中间文件中最后将加了行号的中间文件内容再写入原文件并删除中间文件。
@ -307,7 +307,7 @@ int main() {
{{< figure src="https://gcore.jsdelivr.net/gh/game-loader/picbase@master/uPic/1011FgrC32.png" >}} {{< figure src="https://gcore.jsdelivr.net/gh/game-loader/picbase@master/uPic/1011FgrC32.png" >}}
5. **定义一个保存学生信息的结构体STUDENT包含的学生信息有学号、姓名、专业和平均分。其中学号和平均分使用整型姓名和专业使用宁符数组。使用动态数组存储学生信息并编写菜单实现学生信息的录入、删除和显示功能。由手录入学生的数量未知因此要使用new运算符实现动态内存的分配、使用delete运算符实现动态内存的回收。另外使用标准流对象cin和cout完𢦓数据的输入输出使用函数重载(例如添加学生到数组时可以采用不同的参数列表、显示学生信息时可以指定成绩区间等)、默认形参、引用变量;以上功能实现在自定义的名字空间中(建议使用学号做名字空间)。** 1. **定义一个保存学生信息的结构体STUDENT包含的学生信息有学号、姓名、专业和平均分。其中学号和平均分使用整型姓名和专业使用宁符数组。使用动态数组存储学生信息并编写菜单实现学生信息的录入、删除和显示功能。由手录入学生的数量未知因此要使用new运算符实现动态内存的分配、使用delete运算符实现动态内存的回收。另外使用标准流对象cin和cout完𢦓数据的输入输出使用函数重载(例如添加学生到数组时可以采用不同的参数列表、显示学生信息时可以指定成绩区间等)、默认形参、引用变量;以上功能实现在自定义的名字空间中(建议使用学号做名字空间)。**
定义命名空间为zqy19281235定义STUDENT结构体定义添加学生函数使用默认形参和引用变量。考虑到学号的唯一性使用map模板来存储学生信息。并将map通过引用传入函数通过学号删除学生信息并释放申请的内存重载显示学生信息的函数当不输入指定的成绩区间时默认全部显示当输入指定成绩区间时可以仅指定最大值或者最小值另一个使用默认形参进行处理。代码如下 定义命名空间为zqy19281235定义STUDENT结构体定义添加学生函数使用默认形参和引用变量。考虑到学号的唯一性使用map模板来存储学生信息。并将map通过引用传入函数通过学号删除学生信息并释放申请的内存重载显示学生信息的函数当不输入指定的成绩区间时默认全部显示当输入指定成绩区间时可以仅指定最大值或者最小值另一个使用默认形参进行处理。代码如下
@ -458,3 +458,655 @@ int main() {
- 删除学生信息 - 删除学生信息
{{< figure src="https://gcore.jsdelivr.net/gh/game-loader/picbase@master/uPic/1012uB9SkP.png" >}} {{< figure src="https://gcore.jsdelivr.net/gh/game-loader/picbase@master/uPic/1012uB9SkP.png" >}}
## 第四次作业 {#第四次作业}
### 设计并测试一个名为Rectangle的矩形类其属性为矩形的左下角与右上角两个点的坐标提供能计算矩形的面积的成员函数。 {#设计并测试一个名为rectangle的矩形类-其属性为矩形的左下角与右上角两个点的坐标-提供能计算矩形的面积的成员函数}
设计一个结构体表示点坐标设计矩形类的属性为两个坐标成员函数为计算面积。并在main函数中简单测试代码如下
```C++
#include <cstdio>
#include <fstream>
#include <iostream>
#include <map>
#include <sstream>
#include <string>
#include <vector>
typedef struct point {
int x;
int y;
} Point;
// 方形类
class Rectangle {
public:
Point left_bottom;
Point right_top;
Rectangle(Point left, Point right) {
left_bottom.x = left.x;
left_bottom.y = left.y;
right_top.x = right.x;
right_top.y = right.y;
};
int area() {
return abs(right_top.x - left_bottom.x) * abs(right_top.y - left_bottom.y);
}
};
int main(int argc, char *argv[]) {
Point point1 = {1, 1};
Point point2 = {2, 3};
Rectangle *rec1 = new Rectangle(point1, point2);
printf("%d", rec1->area());
return 0;
}
```
测试结果如下
{{< figure src="https://gcore.jsdelivr.net/gh/game-loader/picbase@master/uPic/1026iUdZ0b.png" >}}
### 设计一个用于人事管理的“人员”类。由于考虑到通用性,这里只抽象出所有类型人员都具有的属性:编号、性别、出生日期、身份证号等。其中“出生日期”声明为一个“日期”类内嵌对象。用成员函数实现对人员信息的录入和显示。要求包括:构造函数和析构函数、拷贝构造函数、内联成员函数、带默认形参值的成员函数、类的组合。 {#设计一个用于人事管理的-人员-类-由于考虑到通用性-这里只抽象出所有类型人员都具有的属性-编号-性别-出生日期-身份证号等-其中-出生日期-声明为一个-日期-类内嵌对象-用成员函数实现对人员信息的录入和显示-要求包括-构造函数和析构函数-拷贝构造函数-内联成员函数-带默认形参值的成员函数-类的组合}
```C++
#include <cstdio>
#include <fstream>
#include <iostream>
#include <map>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
class date {
public:
string birthday;
};
class Person {
public:
string pno;
string sex;
string idno;
Person();
Person(const Person &obj);
void add(string x, string y, string z, string xx);
inline void display();
~Person();
private:
date date_;
};
Person::Person() {}
Person::~Person() {}
Person::Person(const Person &obj) {
cout << "call copy function";
pno = obj.pno;
sex = obj.sex;
idno = obj.idno;
date_.birthday = obj.date_.birthday;
}
void Person::add(string x, string y, string z, string xx = "00000000") {
pno = x;
sex = y;
idno = xx;
date_.birthday = z;
}
inline void Person::display() {
cout << "Info of this Person is: " << endl
<< "No: " << pno << "\tSex: " << sex << "\tBirthday:" << date_.birthday
<< "\tIdno" << idno << endl;
}
```
### 定义一个Cat类拥有静态数据成员HowManyCats记录Cat的对象个体数目静态成员函数GetHowMany()存取HowManyCats。非静态数据成员CatID记录当前对象的编号成员函数GetCatID()存取CatID。设计程序测试这个类生成若干个Cat对象输出每个对象的数据成员值体会静态成员和非静态成员的用法。 {#定义一个cat类-拥有静态数据成员howmanycats-记录cat的对象个体数目-静态成员函数gethowmany-存取howmanycats-非静态数据成员catid记录当前对象的编号-成员函数getcatid存取catid-设计程序测试这个类-生成若干个cat对象-输出每个对象的数据成员值-体会静态成员和非静态成员的用法}
```C++
#include <cstdio>
#include <fstream>
#include <iostream>
#include <map>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
class Cat {
public:
static int HowManyCats;
static void GetHowMany() { cout << HowManyCats << endl; }
string CatID;
void GetCatID() { cout << CatID << endl; }
Cat(string);
~Cat();
private:
};
int Cat::HowManyCats = 0;
Cat::Cat(string id) {
HowManyCats++;
CatID = id;
}
Cat::~Cat() { HowManyCats--; }
int main(int argc, char *argv[]) {
string IDs[5] = {"aaaaaaaa", "bbbbbbbbb", "cccccc", "dddddddd", "eeeeeeeee"};
vector<Cat *> cats;
// 实例化Cat
for (int i = 0; i < 5; i++) {
Cat *newcat = new Cat(IDs[i]);
cats.push_back(newcat);
}
// 打印所有对象
for (int i = 0; i < 5; i++) {
cats[i]->GetCatID();
cats[i]->GetHowMany();
delete cats[i];
}
return 0;
}
```
定义Cat类后在main中实例化五个Cat并输出。输出时输出CatID和HowManyCats。随后删除该实例。在构造函数中每实例化一个Cat就将HowManyCats加一。删除时则减一。测试结果如下
{{< figure src="https://gcore.jsdelivr.net/gh/game-loader/picbase@master/uPic/1027RWGklD.png" >}}
### 4 {#4}
> 设计一个字符串类MyString要求如下
>
> (1) 正确封装数据,要求使用动态内存分配的方式管理封装的数据;
>
> (2) 正确实现构造函数和析构函数,正确初始化数据,防止内存泄露;构造函数要有多个重载版本;
>
> (3) 实现存取字符串的功能其中取字符串的函数为get_string存字符串的函数为set_string
>
> (4) 实现追加字符串的功能、取得字符串长度的功能;
>
> (5) 要求类的声明写在MyString.h文件中类的实现写在MyString.cpp文件中。
>
> 编写函数测试你所设计的类。
使用char指针指示字符串在构造函数和set_string中为指针动态分配内存并将字符串拷贝过去连接字符串则重新申请空间并释放之前申请的空间然后进行字符串的拷贝。代码如下
```C++
// MyString.h
#include <cstdio>
#include <fstream>
#include <iostream>
#include <map>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
class MyString {
private:
char *str;
int length;
public:
MyString();
MyString(const char *s);
char *get_string();
void set_string(char *s);
int get_length();
void append(char *s);
~MyString();
};
```
```C++
// MyString.cpp
#include "MyString.h"
#include <cstring>
using namespace std;
MyString::MyString(const char *s) {
length = strlen(s);
str = new char[length + 1];
str[length] = '\0';
//安全拷贝
strncpy(str, s, length + 1);
}
MyString::~MyString(){};
char *MyString::get_string() { return str; }
void MyString::set_string(char *s) {
length = strlen(s);
str = new char[length + 1];
str[length] = '\0';
//安全拷贝
strncpy(str, s, length + 1);
}
int MyString::get_length() { return length; }
void MyString::append(char *s) {
length = length + strlen(s);
char *str_temp = new char[length + 1];
str_temp[length] = '\0';
strncpy(str_temp, str, length + 1);
strncat(str_temp, s, length + 1);
delete str;
str = str_temp;
}
int main(int argc, char *argv[]) {
char *first = "This is first string";
char *second = "This is second";
MyString mystring(first);
cout << "Length: " << mystring.get_length() << endl;
cout << "String is : " << mystring.get_string() << endl;
// 添加第二字符串
mystring.append(second);
cout << "Length: " << mystring.get_length() << endl;
cout << "String is : " << mystring.get_string() << endl;
return 0;
}
```
在main中定义两个字符串并测试得
{{< figure src="https://gcore.jsdelivr.net/gh/game-loader/picbase@master/uPic/1027hTiJxJ.png" >}}
### 5 {#5}
> 尝试封装学生列表类。对于学生信息包含姓名、学号、成绩等封装一个学生列表类CStudentList在这个类中实现增加、按学号删除、修改学生信息、显示学生信息的功能其中保存学生的信息应该使用动态内存的方法以实现保存"无限"的学生信息。其他要求如下:
>
> (1) 至少显示学生信息的函数要有重载版本,比如可选择根据学生学号显示学生信息、根据学生成绩显示学生信息、根据给定的成绩区间显示学生的信息(此时要练习默认形参值)。
>
> (2) 练习引用,比如可设计根据姓名取得学生信息并以引用的形式返回该学生信息的函数;对于按引用返回的学生信息,可实现修改其成绩的功能。
>
> (3) 学生信息可以仍然使用结构体来表示。
>
> (4) 重点是懂得封装的思想,理解构造函数和析构函数的设计和使用。
>
> 注意:由于还没有介绍复制构造函数和赋值运算符函数,所以该类会有不少问题,但对于简单的增加、按学号删除和显示学生信息的功能,还是要能够正常运行的。
这个学生类中的部分函数在之前作业中已经实现过,这里就直接拿来使用。主要是要将函数和数据进行封装。代码如下
```C++
#include <cstdio>
#include <fstream>
#include <iostream>
#include <map>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
using namespace std;
struct STUDENT {
int sno;
string name;
string specialty;
int average;
};
class Stu_info {
public:
Stu_info(){};
~Stu_info(){};
// 有默认形参,使用引用变量
void add_stu(map<int, struct STUDENT *> &students, int sno, string name,
string specialty, int average = 60) {
struct STUDENT *new_stu = new (struct STUDENT);
new_stu->sno = sno;
new_stu->name = name;
new_stu->specialty = specialty;
new_stu->average = average;
students.insert(make_pair(sno, new_stu));
}
void del_stu(map<int, struct STUDENT *> &students, int sno) {
// 释放内存
delete (students.find(sno)->second);
students.erase(sno);
cout << "Delete success!";
}
// 默认全部显示
void look_up_stu(map<int, struct STUDENT *> &students) {
for (auto stu : students) {
cout << "Sno = " << stu.second->sno << " Name = " << stu.second->name
<< " Specialty = " << stu.second->specialty
<< " Score = " << stu.second->average << endl;
}
}
// 重载的显示函数
void look_up_stu(map<int, struct STUDENT *> &students, int flag, int min = 0,
int max = 100) {
for (auto stu : students) {
if (stu.second->average >= min && stu.second->average <= max) {
cout << "Sno = " << stu.second->sno << " Name = " << stu.second->name
<< " Specialty = " << stu.second->specialty
<< " Score = " << stu.second->average << endl;
}
}
}
};
int main() {
char select;
cout << "Welcome to my student manage system!!!!!" << endl;
Stu_info *stu_info = new Stu_info();
map<int, STUDENT *> students;
while (true) {
cout << "\nPlease select the operation you want:" << endl
<< "\t1.add a student.\n"
<< "\t2.delete a student\n"
<< "\t3.display students infomation\n"
<< "\tq for quit\n"
<< "your select:";
cin >> select;
switch (select) {
case '1': {
int number, average;
string aver;
string name, specialty;
cout << "The student number:";
cin >> number;
cout << "The student name:";
cin >> name;
cout << "The student specialty:";
cin >> specialty;
cin.get();
cout << "The student score(can be nothing):";
getline(cin, aver);
if (aver.length() == 0) {
stu_info->add_stu(students, number, name, specialty);
} else {
average = stoi(aver);
stu_info->add_stu(students, number, name, specialty, average);
}
break;
}
case '2': {
int number;
cout << "The student number:";
cin >> number;
stu_info->del_stu(students, number);
break;
}
case '3': {
string min, max;
cout << "Enter the min score of the students:";
cin.get();
getline(cin, min);
cout << "Enter the max score of the students:";
getline(cin, max);
if (min.length() == 0 && max.length() == 0) {
stu_info->look_up_stu(students);
break;
} else if (max.length() == 0) {
stu_info->look_up_stu(students, 1, stoi(min));
} else if (min.length() == 0) {
stu_info->look_up_stu(students, 1, 0, stoi(max));
} else {
stu_info->look_up_stu(students, 1, stoi(min), stoi(max));
}
break;
}
case 'q': {
return 0;
}
default:
break;
}
}
}
```
测试结果如下:
{{< figure src="https://gcore.jsdelivr.net/gh/game-loader/picbase@master/uPic/1028t4AFaW.png" >}}
### 编程题1 {#编程题1}
> 编写并测试一个单件类:该类能够控制系统中最多只存在一个该类的对象。
该题其实背后涉及的原理很复杂在查阅资料后可以找到一种最简洁的实现方式该方式也被称为Meyers' Singleton.其实现代码如下
```C++
#include <cstdio>
#include <fstream>
#include <iostream>
#include <map>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
using namespace std;
class Singleton {
private:
Singleton() { test = 0; };
~Singleton(){};
Singleton(const Singleton &);
Singleton &operator=(const Singleton &);
public:
int test;
static Singleton *getInstance() {
static Singleton instance;
return &instance;
}
};
int main(int argc, char *argv[]) {
Singleton *object1 = Singleton::getInstance();
object1->test = 1;
Singleton *object2 = Singleton::getInstance();
printf("%d", object2->test);
return 0;
}
```
这里使用了静态局部变量该变量在第一次调用getInstance函数时会被初始化在之后即便再次调用getInstance函数该变量的地址也不会变化即在该函数内该变量唯一。这一点可以通过main中的测试来说明首先调用公有的静态方法获取一个实例。然后修改实例中的test。因为构造函数中test的值为0若再次获取到的为新实例则object2的test值应为0但实际运行结果如下
{{< figure src="https://gcore.jsdelivr.net/gh/game-loader/picbase@master/uPic/1028sPiBf8.png" >}}
这说明object2获取到的仍然为同一实例打印指针可更直观的了解object1、2为同一实例。
{{< figure src="https://gcore.jsdelivr.net/gh/game-loader/picbase@master/uPic/1028wdh3Oj.png" >}}
### 编程题2 {#编程题2}
> 魔兽世界之一备战描述魔兽世界的西面是红魔军的司令部东面是蓝魔军的司令部。两个司令部之间是依次排列的若干城市。红司令部City 1City 2........City n蓝司令部两军的司令部都会制造武士。武士一共有 dragon 、ninja、iceman、lion、wolf 五种。每种武士都有编号、生命值、攻击力这三种属性。双方的武士编号都是从1开始计算。红方制造出来的第n个武士编号就是n。同样蓝方制造出来的第n个武士编号也是n。武士在刚降生的时候有一个生命值。在每个整点双方的司令部中各有一个武士降生。红方司令部按照iceman、lion、wolf、ninja、dragon的顺序循环制造武士。蓝方司令部按照lion、dragon、ninja、iceman、wolf的顺序循环制造武士。制造武士需要生命元。制造一个初始生命值为m的武士司令部中的生命元就要减少m个。如果司令部中的生命元不足以制造某个按顺序应该制造的武士那么司令部就试图制造下一个。如果所有武士都不能制造了则司令部停止制造武士。给定一个时间和双方司令部的初始生命元数目要求你将从0点0分开始到双方司令部停止制造武士为止的所有事件按顺序输出。一共有两种事件其对应的输出样例如下
>
> 1. 武士降生输出样例: 004 blue lion 5 born with strength 5,2 lion in red headquarter
> 表示在4点整编号为5的蓝魔lion武士降生它降生时生命值为5降生后蓝魔司令部里共有2个lion武士。为简单起见不考虑单词的复数形式注意每制造出一个新的武士都要输出此时司令部里共有多少个该种武士。
> 2. 司令部停止制造武士输出样例: 010 red headquarter stops making warriors
> 表示在10点整红方司令部停止制造武士输出事件时首先按时间顺序输出同一时间发生的事件先输出红司令部的再输出蓝司令部的。输入第一行是一个整数代表测试数据组数。每组测试数据共两行。第一行一个整数M。其含义为 每个司令部一开始都有M个生命元( 1 &lt;= M &lt;= 10000)。第二行:五个整数,依次是 dragon 、ninja、iceman、lion、wolf 的初始生命值。它们都大于0小于等于10000。输出对每组测试数据要求输出从0时0分开始到双方司令部都停止制造武士为止的所有事件。对每组测试数据首先输出"Case:n" n是测试数据的编号从1开始 。接下来按恰当的顺序和格式输出所有事件。每个事件都以事件发生的时间开头,时间以小时为单位,有三位。样例输入
> 1
> 20
> 3 4 5 6 7
> 样例输出
> Case:1
> 000 red iceman 1 born with strength 5,1 iceman in red headquarter
> 000 blue lion 1 born with strength 6,1 lion in blue headquarter
> 001 red lion 2 born with strength 6,1 lion in red headquarter
> 001 blue dragon 2 born with strength 3,1 dragon in blue headquarter
> 002 red wolf 3 born with strength 7,1 wolf in red headquarter
> 002 blue ninja 3 born with strength 4,1 ninja in blue headquarter
> 003 red headquarter stops making warriors
> 003 blue iceman 4 born with strength 5,1 iceman in blue headquarter
> 004 blue headquarter stops making warriors
这道题题面比较复杂。但是仔细分析后可知指挥部只有制造武士这一种行为实际上比较简单。只需读取输入为每个武士赋予相应的属性即可。这里因为武士本身没有行为可以使用结构体存储。司令部为一个类其中包含了生命元数量制造武士顺序现在制造的武士的下标司令部的颜色武士的标号和所有武士的信息这几个成员变量。使用武士名作为key构造哈希表存储武士信息可以快速获得某种武士的数量。构造函数中初始化成员变量。成员函数为制作武士和判断两个函数。制造武士用于根据指定下标制造对应顺序的武士判断则用于判断当前应制造的武士能否制造不能则寻找下一个能制造的武士如果已经不能制造则终止制造武士并将over置为true;
代码如下
```C++
#include <cstdio>
#include <fstream>
#include <iostream>
#include <map>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
using namespace std;
typedef struct own_warrior {
int number;
int life_value;
int attacker;
} own_warrior;
struct warrior {
string name;
int life_value;
};
// 构造战士信息哈希表
map<int, struct warrior *> warriors;
vector<string> warrior_name = {"dragon", "ninja", "iceman", "lion", "wolf"};
class headquarter {
public:
int meta_life;
vector<int> order;
int warrior_now;
bool over;
string color;
int warrior_num;
map<string, vector<struct own_warrior *> *> warrior_info;
headquarter(int, vector<int>, string);
headquarter(headquarter &&) = default;
headquarter(const headquarter &) = default;
headquarter &operator=(headquarter &&) = default;
headquarter &operator=(const headquarter &) = default;
~headquarter();
void make_warrior(int);
void judge_make();
private:
};
// 构造函数,初始化生命元和战士信息
headquarter::headquarter(int life, vector<int> my_order, string my_color) {
meta_life = life;
order = my_order;
color = my_color;
warrior_num = 1;
over = false;
warrior_now = 0;
for (int i = 0; i < warrior_name.size(); i++) {
vector<struct own_warrior *> *temp_vector =
new vector<struct own_warrior *>;
warrior_info.insert(make_pair(warrior_name[i], temp_vector));
}
}
headquarter::~headquarter() {}
// 制造战士
void headquarter::make_warrior(int warr_now) {
int life_value = warriors[order[warr_now]]->life_value;
string name = warriors[order[warr_now]]->name;
// 为新战士分配内存空间放入对应的map中
own_warrior *new_warrior = new own_warrior;
new_warrior->number = warrior_num;
new_warrior->life_value = life_value;
new_warrior->attacker = 0;
warrior_info[name]->push_back(new_warrior);
cout << color << " " << warriors[order[warr_now]]->name << " " << warrior_num
<< " born with strength " << warriors[order[warr_now]]->life_value << ","
<< warrior_info[name]->size() << " " << name << " in " << color
<< " headquarter" << endl;
warrior_num++;
warrior_now = (warr_now + 1) % (warriors.size());
// cout << warriors.size() << " " << warrior_now << endl;
meta_life -= life_value;
return;
}
// 判能否制造下一个战士,不能则继续制造下一个,直到都不能则结束.
void headquarter::judge_make() {
if (warriors[order[warrior_now]]->life_value <= meta_life) {
make_warrior(warrior_now);
return;
} else {
for (int i = 1; i < warriors.size(); i++) {
if (warriors[order[(warrior_now + i) % warriors.size()]]->life_value <=
meta_life) {
warrior_now = (warrior_now + i) % warriors.size();
make_warrior(warrior_now);
return;
}
}
over = true;
cout << color << " headquarter stops making warriors" << endl;
return;
}
}
int main(int argc, char *argv[]) {
int case_no = 0;
int length = 5;
vector<int> red_order = {2, 3, 4, 1, 0};
vector<int> blue_order = {3, 0, 1, 2, 4};
//处理每组数据
while (cin >> case_no) {
int time = 0;
int case_life = 20;
cin >> case_life;
warriors.clear();
for (int i = 0; i < length; i++) {
int wa_life = 0;
cin >> wa_life;
struct warrior *new_warrior = new struct warrior;
new_warrior->life_value = wa_life;
new_warrior->name = warrior_name[i];
warriors.insert(make_pair(i, new_warrior));
}
headquarter *red_headquarter = new headquarter(case_life, red_order, "red");
headquarter *blue_headquarter =
new headquarter(case_life, blue_order, "blue");
cout << "Case:" << case_no << endl;
while (!red_headquarter->over || !blue_headquarter->over) {
if (!red_headquarter->over) {
printf("%03d ", time);
red_headquarter->judge_make();
}
if (!blue_headquarter->over) {
printf("%03d ", time);
blue_headquarter->judge_make();
}
time++;
}
}
return 0;
}
```
运行结果如下
{{< figure src="https://gcore.jsdelivr.net/gh/game-loader/picbase@master/uPic/10290QUmPy.png" >}}