总时间限制: 1000ms 内存限制: 65536kB
描述
魔兽世界的西面是红魔军的司令部,东面是蓝魔军的司令部。两个司令部之间是依次排列的若干城市。
红司令部,City 1,City 2,……,City n,蓝司令部
两军的司令部都会制造武士。武士一共有 dragon 、ninja、iceman、lion、wolf 五种。每种武士都有编号、生命值这两种属性。
有的武士可以拥有武器。武器有三种,sword, bomb,和arrow,编号分别为0,1,2。
双方的武士编号都是从1开始计算。红方制造出来的第 n 个武士,编号就是n。同样,蓝方制造出来的第 n 个武士,编号也是n。
不同的武士有不同的特点。
dragon 可以拥有一件武器。编号为n的dragon降生时即获得编号为 n%3 的武器。dragon还有“士气”这个属性,是个浮点数,其值为它降生后其司令部剩余生命元的数量除以造dragon所需的生命元数量。
ninja可以拥有两件武器。编号为n的ninja降生时即获得编号为 n%3 和 (n+1)%3的武器。
iceman有一件武器。编号为n的iceman降生时即获得编号为 n%3 的武器。
lion 有“忠诚度”这个属性,其值等于它降生后其司令部剩余生命元的数目。
wolf没特点。
请注意,在以后的题目里,武士的士气,生命值,忠诚度在其生存期间都可能发生变化,都有作用,武士手中的武器随着使用攻击力也会发生变化。
武士在刚降生的时候有一个生命值。
在每个整点,双方的司令部中各有一个武士降生。
红方司令部按照 iceman、lion、wolf、ninja、dragon 的顺序循环制造武士。
蓝方司令部按照 lion、dragon、ninja、iceman、wolf 的顺序循环制造武士。
制造武士需要生命元。
制造一个初始生命值为 m 的武士,司令部中的生命元就要减少 m 个。
如果司令部中的生命元不足以制造某个按顺序应该制造的武士,那么司令部就试图制造下一个。如果所有武士都不能制造了,则司令部停止制造武士。
给定一个时间,和双方司令部的初始生命元数目,要求你将从0点0分开始到双方司令部停止制造武士为止的所有事件按顺序输出。
一共有两种事件,其对应的输出样例如下:
- 武士降生
输出样例: 004 blue lion 5 born with strength 5,2 lion in red headquarter
表示在 4点整,编号为5的蓝魔lion武士降生,它降生时生命值为5,降生后蓝魔司令部里共有2个lion武士。(为简单起见,不考虑单词的复数形式)注意,每制造出一个新的武士,都要输出此时司令部里共有多少个该种武士。
如果造出的是dragon,那么还要输出一行,例:
It has a arrow,and it’s morale is 23.34
表示该dragon降生时得到了arrow,其士气是23.34(为简单起见,本题中arrow前面的冠词用a,不用an,士气精确到小数点后面2位,四舍五入)
如果造出的是ninja,那么还要输出一行,例:
It has a bomb and a arrow
表示该ninja降生时得到了bomb和arrow。
如果造出的是iceman,那么还要输出一行,例:
It has a sword
表示该iceman降生时得到了sword。
如果造出的是lion,那么还要输出一行,例:
It’s loyalty is 24
表示该lion降生时的忠诚度是24。 - 司令部停止制造武士
输出样例: 010 red headquarter stops making warriors
表示在 10点整,红方司令部停止制造武士
输出事件时:
首先按时间顺序输出;
同一时间发生的事件,先输出红司令部的,再输出蓝司令部的。
输入
第一行是一个整数,代表测试数据组数。
每组测试数据共两行。
第一行,一个整数M。其含义为: 每个司令部一开始都有M个生命元( 1 <= M <= 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
It has a bomb
000 blue lion 1 born with strength 6,1 lion in blue headquarter
It's loyalty is 14
001 red lion 2 born with strength 6,1 lion in red headquarter
It's loyalty is 9
001 blue dragon 2 born with strength 3,1 dragon in blue headquarter
It has a arrow,and it's morale is 3.67
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
It has a sword and a bomb
003 red headquarter stops making warriors
003 blue iceman 4 born with strength 5,1 iceman in blue headquarter
It has a bomb
004 blue headquarter stops making warriors
相比较备战,这次的武士多出了个性,故每种武士不单单是一个名字,需要从武士类派生定制个性;
需要在派生出的武士类中添加该派生类的武器即可。
武士 分为5种
武器 分为 swor、bomb 、arrow 三种
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
#define WARRIOR_NUM 5 //武士数
#define WEAPON_NUM 3 //武器数
#define MAX_WARRIORS 1000 //武士最大数量
enum { DRAGON,NINJA,ICEMAN,LION,WOLF}; //枚举,即dragon=0,ninja=1,2,3,4
武器类的定义
武器有序号——0-2
武器有攻击力——本题未定义
静态变量——与武器类相关的全局变量,分别为武器的攻击力列表,武器名字的列表
均可由武器的序号得到
class CWeapon
{
public:
int nKindNo; //序号
int nForce; //攻击力
static int InitialForce[WEAPON_NUM]; //武器初始攻击力列表
static const char *Names[WEAPON_NUM]; //武器名字的列表
};
武士类的定义
武士的属性:所属司令部颜色,所拥有生命值,所拥有武器,种类名,序号
武士的制造顺序与基地的颜色有关
武士的制造结束与基地的生命值有关
故需要指向基地的指针,得到基地的有关参数
class CHeadquarter; //声明司令类
class CWarrior{
protected: //保护,派生可以访问当前对象的protect内容
CHeadquarter *pHeadquarter; //指向该武士基地的指针,用于得到基地的颜色,基地的生命值
int nNo; //武士的编号,用于武士计数
public:
static const char*Names[WARRIOR_NUM]; //静态数组——武士名字
static int InitialLifeValue[WARRIOR_NUM]; //静态数组——每种武士的初始生命值
CWarrior(CHeadquarter * p, int nNo_); //武士构造函数——输入基地指针,武士编号
virtual void PrintResult(int nTime,int nKindNo); //虚函数——输出函数——此为通用输出函数
virtual void PrintResult(int nTime) =0; //虚函数——输出函数———此为派生类的个性输出函数
virtual ~CWarrior(){} //虚函数——析构函数
};
司令类的定义
司令类的有颜色和生命值两个属性;
为输出服务的成员:
为判断能否继续生产武士,添加stop成员;
要输出每种武士的个数,故需要anWarriorNum列表,记录每种武士的个数;
需要确定当前制造武士的种类,可由武士总数/循环个数得出;
需要列表保存以生产的每一个武士,方便进行后续处理;
class CHeadquarter //定义司令部
{
private:
int nTotalLifeValue; //基地总生命值
bool bStopped; //是否停止制造
int nColor; //基地颜色
int nCurMakingSeqIdx; //当前正在制造的武士序列号
int anWarriorNum[WARRIOR_NUM]; //每种武士的数量
int nTotalWarriorNum; //总武士数量
CWarrior * pWarriors[MAX_WARRIORS];
public:
friend class CWarrior; //友元武士,武士类可访问司令类private
static int MakingSeq[2][WARRIOR_NUM]; //制作顺序表,
void Init(int nColor_, int lv); //声明初始函数——颜色,生命值
~CHeadquarter(); //声明析构函数
int Produce(int nTime); //声明生产函数,需要输入当前时间
void GetColor(char * szColor); //声明函数,得到当前基地的颜色
int GetTotalLifeValue() { return nTotalLifeValue;} //声明函数,得到当前基地的生命值
};
派生类的定义
class CDragon:public CWarrior{ //武士派生
//dragon 拥有武器和士气
//武器:编号为n%3,n为dragon的编号
//士气:降生后司令部剩余生命元的数量除以造dragon所需的生命元数量,double类型
private:
CWeapon wp; //武器
double fmorale; //忠诚度
public:
void Countmorale()
{ //指向司令部的指针——得到司令部的生命值
fmorale = pHeadquarter -> GetTotalLifeValue()/(double)CWarrior::InitialLifeValue[0];
//序号0为dragon
}
CDragon( CHeadquarter *p, int nNo_): CWarrior(p,nNo_){
//初始构造函数,基类有的与基类相同
wp.nKindNo = nNo % WEAPON_NUM; //武器种类构造
wp.nForce = CWeapon::InitialForce[wp.nKindNo]; //攻击力数值构造
Countmorale(); //士气构造
}
void PrintResult(int nTime) //虚函数
{
CWarrior::PrintResult(nTime,DRAGON); //调用基类的printresult
printf("It has a %s,and it's morale is %.2f\n",CWeapon::Names[wp.nKindNo],fmorale);
//Dragon类特有的输出
}
};
class CNinja:public CWarrior
{
private:
CWeapon wps[2]; //派生出2把武器
public:
CNinja(CHeadquarter *p, int nNo_): CWarrior(p,nNo_) //得到基类的构造
{ //添加武器的构造方法
wps[0].nKindNo=nNo%WEAPON_NUM; //确定武器序号
wps[0].nForce = CWeapon::InitialForce[wps[0].nKindNo]; //确定武器攻击力
wps[1].nKindNo=(nNo+1)%WEAPON_NUM;
wps[1].nForce = CWeapon::InitialForce[wps[1].nKindNo]; //武器类里的该种武器的攻击力
}
void PrintResult(int nTime) //输出函数
{
CWarrior::PrintResult(nTime,NINJA);
//此处NINJA为开头的序号 ,先调用武士类的print函数
printf("It has a %s and a %s\n",CWeapon::Names[wps[0].nKindNo],CWeapon::Names[wps[1].nKindNo]);
//再输出两把武器的名字
}
};
class CIceman:public CWarrior{
private:
CWeapon wp;
public:
CIceman(CHeadquarter * p, int nNo_):CWarrior(p,nNo_) //构造函数
{
wp.nKindNo=nNo % WEAPON_NUM;
wp.nForce=CWeapon::InitialForce[wp.nKindNo];
}
void PrintResult(int nTime)
{
CWarrior::PrintResult(nTime,ICEMAN);
printf("It has a %s\n",CWeapon::Names[wp.nKindNo]); //输出该武士的武器
}
};
class CLion:public CWarrior
{
private:
int nLoyalty; //忠诚度
public:
void CountLoyalty() //定义函数,得到nloyalty
{
nLoyalty=pHeadquarter->GetTotalLifeValue();
}
CLion(CHeadquarter *p, int nNo_):CWarrior(p,nNo_){ //构造函数——调用父类
CountLoyalty(); //赋值nloyalty
}
void PrintResult(int nTime)
{
CWarrior::PrintResult(nTime,LION);
CountLoyalty();
printf("It's loyalty is %d\n",nLoyalty);
}
};
class CWolf:public CWarrior{
public:
CWolf(CHeadquarter *p, int nNo_): CWarrior(p,nNo_){} //构造函数,与父类完全相同
void PrintResult(int nTime)
{
CWarrior::PrintResult(nTime,WOLF); //print函数,与父类相同
}
};
补充武士类的内部函数
1.构造函数
CWarrior::CWarrior(CHeadquarter *p,int nNo_) //武士类构造函数
{
nNo=nNo_;
pHeadquarter =p;
}
2.输出函数
制造该武士的时间
输出该武士的司令部颜色
武士的序号,
武士的种类,
武士种类的个数——该属性保存司令部中
武士的生命值;
void CWarrior::PrintResult(int nTime, int nKindNo) //双参数的武士类print函数
{ //要输出的时间数,武士的种类
char szColor[20];
pHeadquarter->GetColor(szColor); //得到当前司令部颜色,防暑szColor中
printf("%03d %s %s %d born with strength %d,%d %s in %s headquarter\n",
nTime,szColor,Names[nKindNo],nNo,InitialLifeValue[nKindNo],pHeadquarter->anWarriorNum[nKindNo],Names[nKindNo],szColor);
}
补充司令部的内部函数
1.司令部初始化函数
void CHeadquarter::Init(int nColor_, int lv) //司令部初始化函数
{
nColor= nColor_;
nTotalLifeValue = lv;
bStopped = false;
nCurMakingSeqIdx=0;
nTotalWarriorNum=0;
for(int i=0;i<WARRIOR_NUM;i++)
anWarriorNum[i]=0;
}
2.司令部析构函数
因pWarrior为动态数组,结束后需要全部释放
CHeadquarter::~CHeadquarter(){ //司令部析构函数
int i;
for (i=0;i<nTotalWarriorNum;i++)
delete pWarriors[i]; //删除武士类列表的信息
}
3.制造函数
用于判断能否制造武士,和输出制造出的武士
先判断停止条件——每一个武士都无法制造
(1)当前武士无法制造,则看下一个武士能否制造,直到看完全部武士
(2)跳出上述循环,依旧无法制造,则返回停止
(3)上述条件不满足,说明可以制造,则开始制造
制造武士
(1)确定武士种类——通过curMakingSeqIdx得到当前制造武士的种类
(2)由种类确定武士生命值,由武士总数确定当前武士序号,由每种武士个数确定武士的种内序号
(3)基地生命值-=武士生命值
(4)为制造下一个武士做准备
(5)将当前武士保存至勇士列表,利用多态性质调用每种武士的输出函数;
int CHeadquarter::Produce(int nTime) //制造函数
{
int nSearchingTimes=0;
if(bStopped) //停止标记
return 0;
while(CWarrior::InitialLifeValue[MakingSeq[nColor][nCurMakingSeqIdx]]>nTotalLifeValue
&& nSearchingTimes<WARRIOR_NUM) //当前正在造的武士(由基地颜色和制造序号确定)生命值大于基地生命值
{ //且未遍历完每一个武士
nCurMakingSeqIdx=(nCurMakingSeqIdx+1)%WARRIOR_NUM;
nSearchingTimes ++; //查找次数也+1——到5个后停止查找并弹出结束
}
//跳出上述循环时
int nKindNo=MakingSeq[nColor][nCurMakingSeqIdx]; //得到当前要造的武士的序号
if(CWarrior::InitialLifeValue[nKindNo]>nTotalLifeValue) //说明遍历完了每一个武士,都不能造,故停止制造
{
bStopped=true; //停止标记
if(nColor==0) //按基地颜色输出
printf("%03d red headquarter stops making warriors\n",nTime);
else
printf("%03d blue headquarter stops making warriors\n",nTime);
return 0;
}
//说明可以制造武士
nTotalLifeValue -= CWarrior::InitialLifeValue[nKindNo]; //基地总生命值-所制造武士生命值
nCurMakingSeqIdx = (nCurMakingSeqIdx+1)%WARRIOR_NUM; //制造武士序列+1
int nTmp= anWarriorNum[nKindNo]; //得到当前种类武士的已有数量
anWarriorNum[nKindNo]++; //+1
switch(nKindNo){
case DRAGON: //DRAGON=1
pWarriors[nTotalWarriorNum] = new CDragon(this,nTotalWarriorNum+1); //生成动态对象,放入武士列表
break;
case NINJA:
pWarriors[nTotalWarriorNum]= new CNinja(this, nTotalWarriorNum+1); //this为当前基地对象,武士编号
break;
case ICEMAN:
pWarriors[nTotalWarriorNum]= new CIceman(this, nTotalWarriorNum+1);
break;
case LION:
pWarriors[nTotalWarriorNum]= new CLion(this,nTotalWarriorNum+1);
break;
case WOLF:
pWarriors[nTotalWarriorNum]= new CWolf(this,nTotalWarriorNum+1);
break;
}
pWarriors[nTotalWarriorNum]->PrintResult(nTime); //用多态——调用了当前武士对象的printresult函数
nTotalWarriorNum ++; //总武士数+1
return 1;
}
司令部类的颜色函数
将int转化为颜色str
void CHeadquarter::GetColor(char * szColor) //定义getcolor函数
{
if(nColor==0) //0红,1蓝
strcpy(szColor,"red");
else
strcpy(szColor,"blue");
}
静态变量的初始化
const char * CWeapon::Names[WEAPON_NUM] = {"sword","bomb","arrow"}; //武器列表
int CWeapon::InitialForce[WEAPON_NUM]; //武器的攻击力列表——这次未用到
const char *CWarrior::Names[WARRIOR_NUM] = {"dragon","ninja","iceman","lion","wolf"}; //武士列表
int CWarrior::InitialLifeValue[WARRIOR_NUM]; //武士总生命值列表
int CHeadquarter::MakingSeq[2][WARRIOR_NUM] = {{2,3,4,1,0},{3,0,1,2,4}}; //红蓝方制造武士的顺序
主函数
int main(){
int t; //case个数
int m; //基地生命值
CHeadquarter RedHead,BlueHead;
scanf("%d",&t);
int nCaseNo=1; //当前case数
while(t--){
printf("Case:%d\n",nCaseNo++);
scanf("%d",&m); //读入生命值总数
int i;
for (i=0;i<WARRIOR_NUM;i++)
scanf("%d", &CWarrior::InitialLifeValue[i]); //读入每个武士的生命值
// for(i=0;i<WEAPON_NUM;i++)
// scanf("%d",&CWeapon::InitialForce[i]); //读入每把武器的攻击力
RedHead.Init(0,m); //颜色,生命值
BlueHead.Init(1,m);
int nTime=0;
while(true){
int tmp1=RedHead.Produce(nTime); //调用produce即出现输出
int tmp2=BlueHead.Produce(nTime);
if(tmp1==0 && tmp2==0) //生产结束
break; //停止循环
nTime ++;
}
}
return 0;
}