Skip to content

1421: ACM EXPRESS

题目

题目描述

题面故事内容不会影响理解题目内容,可以跳过。以下内容均为虚构,如有与现实雷同纯属巧合。

Send not to know for whom the bell tolls, it tolls for thee.

不要问丧钟为谁耳鸣,丧钟敲响正为你的亡灵。

“…… 现在是灾变 128 年…你说公历?好遥远的概念……应该是…… 2127 年吧。在 1999 年大灾变发生之后,死亡搁浅现象开始在全球各地出现,死亡被搁浅,时间被割裂,国家形态不存。这都是我从历史库中看来的。听说那个时代是所谓 “全球化” 的时代…真是难以想象。人们不需要与他人交流,这才是正常的。

……

生存?开罗尔网络能够打印各种物体,牛排、维生素、能量水、威士忌……生存不是问题。

……

交流、合作、未来?为什么要未来?你知道的,冥滩连接着所有时间,不存在过去与未来,只有当下。

……

祝你好运,不见。”

眼前的视野转入黑暗,耳边响起熟悉的胎儿声与水声,意识重新浮现至水面。

你摘下开罗尔头显,眼前是熟悉的天花板。

你现在在你的房间里,更准确地说,是在 Mindwung 节点城的生活区 X15。你是 ACM Express 的一名文职人员。ACM Express 是在大灾变之后出现的物流公司之一,本部设于 Mindwung 节点城,口碑不错,在 Chining 大陆东部各地都派送过订单。

ACM Express 用 15 年重新在 Chungentrial 地区建立物流基础设施——高空索道、防时间雨高速路、跨泯灭坑隧道。但是,ACM Express 在 Chungentrial 地区的成果并没有给予人们跨越 Qinhwai 泯灭带的信心。所以,他们现在有一个大计划要执行——重振 Chining 国的超级物流系统。如果能将 Peching 接入开罗尔网络,或许人们的想法会有所转变。

公司的科技局正在进行最后的准备,在开罗尔网络中,他们已经找到了真空磁悬浮高铁与反重力运载机的技术,前者能保护车厢通过泯灭区,后者能通过在任何地形。目前,他们缺少了一个关键组件——物流管理系统。物流管理系统的工作被分为多个订单,你在阅览所有订单后认为其中一份订单或许你可以提供帮助:

在本题中,你需要实现四个保存快递信息的类:mailair_mailtrain_mailcar_mail。我们提供一个基类object

```c++ // 你无需修改、提交以下代码,即,你最终的提交 不应该 包含以下代码。 // 本题评测时使用的 object 类存放于名为 base.hpp 的文件里,你最终的提交需要 include 该头文件以避免 ce 。 // 即,你的提交应包含一行 #include "base.hpp" 。

// 以下函数说明只是便于理解,详细的要求见各个派生类的说明。

include

using namespace std; class object { protected: string contain; public: // 构造函数。 object() = default; object(string contain) : contain(contain) {}

// copy 函数,将 o 指针对应的类的信息拷贝到调用该函数的类对象上。
// 保证 o 与 this 是同一种派生类指针,但会以 object * 的形式传入。
// 具体可以参考 main 函数中的调用方式。
virtual void copy(object* o) = 0;

// 参数为某个日期,返回一个字符串,代表此日期快递的派送状态。
virtual string send_status(int y, int m, int d) = 0;

// 返回派送快递的方法。详见各个派生类的说明。
virtual string type() = 0;

// 输出保存于类内的信息,具体格式详见各个派生类的说明。
virtual void print() {
    cout << "[object] contain: " << contain << endl;
    // 注意:本题评测时使用的 object 类会与这里的版本有微小的区别,但不会对于完成本题有影响。
}

// 析构函数。
virtual ~object() {}

}; ```

其中contain为一些存储于object类内的字符串信息。

你需要实现的每个类都需要从object继承(有可能是非直接继承)。具体而言,你需要完成如下继承树:

其中除去object类以外的内容均需要你去实现。

另外,我们还提供一个日期类date

c++ struct date { int year, month, day; date() = default; date(int y, int m, int d) : year(y), month(m), day(d) {} //todo 实现流输入 //todo 实现 operator< 的重载 };

其中你需要实现date类的operator>>重载,使得其支持流输入。具体格式为

c++ <year> <month> <day> // 代表年份为<year>,月份为<month>,日期为<day> 2020 1 2 // 例如,这个输入代表2020年1月2日

你还需要实现operator<的重载,去实现日期类的比较功能。小于的含义是时间上早于。

注意:在本题中,为了简化计算,我们假设一年有360天,一年有12个月,每个月有30天。

在四种mail类中,你均需要实现构造函数、析构函数、copy函数、send_status函数、type函数、print函数,其中析构函数只需保证没有内存泄漏即可,以下不做特别说明;其余函数除去构造函数,参数列表均与object类相同,以下也不做特别说明。这些函数均需要实现override,即,派生类拥有不同的函数实现,使用基类指针调用时优先调用派生类的实现。

作为一种良好的代码风格,除去上述你需要实现的函数应定义成public,你的类内变量以及你需要的内部辅助函数均应定义成protected

以下的说明中,参数均只代表变量类别,你可以自由选择引用传递或值传递;变量名只代表题面中对于该变量的称呼,你可以自由选择变量名。输出格式中被<>包围的信息即你需要输出的变量之名称

mail

mail类中,你需要保存如下信息:

并实现以下函数:

构造函数:参数为

mail(std::string contain, std::string postmark, date send_date, date arrive_date);

,保证send_date < arrive_date

copy:将o指针对应的类的信息拷贝到调用该函数的类对象上。对于mail类,保证omail类的指针,但会以object *的形式传入。

send_status:尚未指定派送方法,快递未送出。返回字符串not send即可。

type:尚未指定派送方法,返回字符串no type即可。

print:首先调用object类的print函数,之后输出一行

[mail] postmark: <postmark>

air_mail

air_mail类中,你需要保存如下信息:

并实现以下函数:

构造函数:参数为

c++ air_mail(std::string contain, std::string postmark, date send_date, date arrive_date, date take_off_date, date land_date, std::string airline);

,保证send_date < take_off_date < land_date < arrive_date

copy:将o指针对应的类的信息拷贝到调用该函数的类对象上。对于air_mail类,保证oair_mail类的指针,但会以object *的形式传入。

send_status:有以下五种可能(记参数中的日期为query_date

type:返回字符串air

print:首先调用mail类的print函数,之后输出一行

[air] airlines: <airlines>

train_mail

train_mail类中,你需要保存如下信息:

并实现以下函数:

构造函数:参数为

c++ train_mail(string _contain_, string _postmark_, date send_d, date arrive_d, string *sname, date *stime, int station_num);

,保证send_datestation_time[0] ~ station_time[station_num - 1]arrive_date单调递增。

copy:将o指针对应的类的信息拷贝到调用该函数的类对象上。对于train_mail类,保证otrain_mail类的指针,但会以object *的形式传入。

send_status:有以下六种可能(记参数中的日期为query_date

type:返回字符串train

print:首先调用mail类的print函数,之后输出一行

[train] station_num: <station_num>

car_mail

car_mail类中,你需要保存如下信息:

并实现以下函数:

构造函数:参数为

c++ car_mail(string _contain_, string _postmark_, date send_d, date arrive_d, int mile, string _driver);

,保证send_date < arrive_date

copy:将o指针对应的类的信息拷贝到调用该函数的类对象上。对于train_mail类,保证otrain_mail类的指针,但会以object *的形式传入。

send_status:有以下三种可能(记参数中的日期为query_date

其中current_mile的计算方法定义为$\frac{\text{已用时间}}{总时间}\times\text{总里程数}$。为了避免精度问题,一律强制类型转换成double再进行运算。 为了保证精度,请使用return to_string(current_mile);

type:返回字符串car

print:首先调用mail类的print函数,之后输出一行

[car] driver_name: <driver_name>

obj_swap

除去以上四个类,你还需要实现一个简单的obj_swap函数,其功能为交换两个object类指针所指对象。注意这可能是两个不同派生类的对象

obj_swap函数的声明为:

c++ void obj_swap(object *&lhs, object *&rhs);

注意事项

本题中,你能够使用的头文件只有iostreamalgorithmbase.hpp,如有其他需要可向助教提问。

请使用cout进行输出。评测程序中关闭了流同步并使用了cout输出,使用printfputs等可能会使输出乱序。

你可能会用到以下知识:

  • reinterpret_cast(it)
  • 可以对指针进行强制类型转换,可以将基类指针强制类型转换为派生类指针使用

作为一个提示,我们给出mail类的copy函数:

c++ void copy(object *o) { contain = reinterpret_cast<mail *>(o) -> contain; postmark = reinterpret_cast<mail *>(o) -> postmark; send_date = reinterpret_cast<mail *>(o) -> send_date; arrive_date = reinterpret_cast<mail *>(o) -> arrive_date; }

调用实例

```c++

include

include

include "src.hpp" // 你提交的代码

using namespace std;

void obj_copy(object ori,object& cop){ string type=ori->type(); if(type=="no type") cop=new mail(); else if(type=="air") cop=new air_mail(); else if(type=="train") cop=new train_mail(); else if(type=="car") cop=new car_mail(); cop->copy(ori); }

const int readinSize=100000; int main(){ ios::sync_with_stdio(false); int mailNum,readSize; cin>>mailNum; object list[readinSize]={nullptr}; for(int i=0;i>type; string contain,postmark; date send_d,arrive_d; cin>>contain>>postmark>>send_d>>arrive_d; if(type=="air"){ date take_off,land; string airline; cin>>take_off>>land>>airline; list[i]=new air_mail(contain,postmark,send_d,arrive_d,take_off,land,airline); }else if(type=="train"){ int station_num; cin>>station_num; string sname; date stime; sname=new string[station_num]; stime=new date[station_num]; for(int j=0;j>sname[j]>>stime[j]; list[i]=new train_mail(contain,postmark,send_d,arrive_d,sname,stime,station_num); delete []sname; delete []stime; }else if(type=="car"){ int mile; string driver; cin>>mile>>driver; list[i]=new car_mail(contain,postmark,send_d,arrive_d,mile,driver); }else if(type=="no"){ list[i]=new mail(contain,postmark,send_d,arrive_d); } } int queryOp; int id; while(cin>>queryOp){ cin>>id; // !following is an example: if(queryOp==0){ cout<type()<print(); }else if(queryOp==2){ int y,m,d; cin>>y>>m>>d; cout<send_status(y,m,d)<>other; obj_swap(list[id],list[other]); }else if(queryOp==4){ //example object tmp; obj_copy(list[id],tmp); delete list[id]; obj_copy(tmp,list[id]); delete tmp; } // !example code finish } delete []list; return 0; } ```

```c++ // src.hpp 框架代码 //代码中的所有内容均可修改

include

include

include "base.hpp"

// !!!如果要新增include文件请举手询问助教 using namespace std;

struct date { int year, month, day; date() = default; date(int y, int m, int d) : year(y), month(m), day(d) {} //todo 需要实现流输入 //todo 增加函数 };

class mail : public object { protected: string postmark; date send_date; date arrive_date;

public: mail() = default;

mail(string _contain_, string _postmark_, date send_d, date arrive_d) : object(_contain_)
{
    postmark = _postmark_;
    send_date = send_d;
    arrive_date = arrive_d;
}

//todo “覆盖”成员函数
//在main.cpp中,所有包裹以object* mail_of_any_type这样一个指针来存储。
//然而直接调用mail_of_any_type->type()或mail_of_any_type->send_status(y, m, d)将调用下列两个基类的成员函数,
//与我们想针对不同类型包裹返回不同形式的内容需求是不符的。
//请修改下面的内容使其满足题意
string send_status(int y, int m, int d)
{
    return "not send";
}

string type()
{
    return "no type";
}

void print()
{
    //todo 调用被“覆盖”前的成员函数
    //这是一个上一todo的对偶问题。即使派生类成员函数已被“覆盖”,怎么才能执行被“覆盖”前的功能?(可以修改函数原型)
    cout << postmark << " by mail" << endl;
}

//已给出copy的实现作为参考
void copy(object *o)
{
    contain = reinterpret_cast<mail *>(o)->contain;
    postmark = reinterpret_cast<mail *>(o)->postmark;
    send_date = reinterpret_cast<mail *>(o)->send_date;
    arrive_date = reinterpret_cast<mail *>(o)->arrive_date;
}

//todo 适当填充函数,注意填充的public函数只能为必须构建的函数(根据派生类的知识,缺少某几个必须的函数将导致该类的对象不能实例化)和重载函数以及构造函数析构函数

};

class air_mail : public mail { protected: string airlines; date take_off_date; date land_date;

public: air_mail() = default;

air_mail(string _contain_, string _postmark_, date send_d, date arrive_d, date take_off, date land, string _airline) : mail(_contain_, _postmark_, send_d, arrive_d)
{
    take_off_date = take_off;
    land_date = land;
    airlines = _airline;
}

string send_status(int y, int m, int d)
{
    date ask_date(y, m, d);
    if (ask_date < send_date)
        return "mail not send";
    else if (ask_date < take_off_date)
        return "wait in airport";
    else if (ask_date < land_date)
        return "in flight";
    else if (ask_date < arrive_date)
        return "already land";
    else
        return "already arrive";
}

string type()
{
    return "air";
}

void print()
{
    //todo
    cout << "[air] airlines: " << airlines << endl;
}

//todo 适当填充函数,注意填充的public函数只能为必须构建的函数(根据派生类的知识,缺少某几个必须的函数将导致该类的对象不能实例化)如重载函数以及构造函数析构函数

};

class train_mail : public mail { protected: string station_name; date station_time; int len;

public: train_mail() = default;

train_mail(string _contain_, string _postmark_, date send_d, date arrive_d, string *sname, date *stime, int station_num){
    //todo
}

string send_status(int y, int m, int d)
{
    //todo
}

string type()
{
    return "train";
}

void print()
{
    //todo
    cout << "[train] station_num: "<<len << endl;
}

//todo 适当填充函数,注意填充的public函数只能为必须构建的函数(根据派生类的知识,缺少某几个必须的函数将导致该类的对象不能实例化)如重载函数以及构造函数析构函数

};

class car_mail : public mail { protected: int total_mile; string driver;

public: car_mail() = default;

car_mail(string _contain_, string _postmark_, date send_d, date arrive_d, int mile, string _driver)
{
    total_mile = mile;
    driver = _driver;
}

string send_status(int y, int m, int d)
{
    //todo
}

string type()
{
    return "car";
}

void print()
{
    //todo
    cout << "[car] driver_name: " + driver << endl;
}
//todo 适当填充函数,注意填充的public函数只能为必须构建的函数(根据派生类的知识,缺少某几个必须的函数将导致该类的对象不能实例化)如重载函数以及构造函数析构函数

};

void obj_swap(object &x, object &y) { //todo 交换两个指针对应的地址的两个对象 } ```

后续

你回到了自己的房间。从 ACM Express Mindwung Site 完成订单回来,听说有三十几个人都接受了这份订单,公司的科技局正在挑选最终方案。物流管理系统是最后一项必须工作,它的完成之时就是 ACM Express “黑水” 计划正式全面开展的时刻。

时间不多了。你已经报名了第二十批远征队的技术支持人员,就在刚才你得知自己被最终选定成为正式队员。你并没有什么特殊的感想,因为尽管你的技术不一定是公司里最好的,但是作为遣返者是远征队亟需的人才。

你从手铐呼出开罗尔网络界面检查随行数据,收起桌面上的开罗尔键鼠,穿上防时间雨冲锋衣……一切就绪。

Let's make Chining shining again!

输入格式

出题人的手稿在运送过程中被时间雨侵蚀,已无法辨别其上的字迹。

输出格式

无法识别

样例输入

无法识别

样例输出

无法识别

数据范围

$0 \le objectNum\le 1e5$

$0\le stationNum\le 1e5$

Oops! 本题目还没有解答!

助教老师们编题的速度,已经超过了解题的速度!

OJ翻了一新,但本解答集还大多用的是2017-2019级,甚至更早的同学们贡献的答案。

如果你已经AC了,可以的话,请您参考添加页面,与大家一起分享你的题解!