课程:北京大学程序设计与算法(三) MOOC
OJ: OpenJudge
013:魔兽世界之一:备战
这个题难度相对比较大,我作为初学者虽然AC了,但代码不够优美。后续等码量足够我会再次更新此题。
1、变量准备
#include<iostream>
#include<iomanip> //格式化
#include<string.h> //string
using namespace std;
int N, m, tim; //总轮数,每一轮司令部生命值,时间
int al[5]; //标准顺序的每种武士生命值
int mmin = 10005; //5种武士生命值的最小值
string biao[5] = { "dragon","ninja","iceman","lion","wolf" };//标准顺序的
string rws[5] = { "iceman","lion","wolf","ninja","dragon" }; //红色司令部的武士顺序
string bws[5] = { "lion","dragon","ninja","iceman","wolf" }; //蓝色司令部的武士顺序
int rwsl[5]; //红色的武士生命值,与其顺序对应
int bwsl[5]; //蓝色的武士生命值,与其顺序对应
因为顺序有一定要求,所以采用常量数组存放。
这些数组通过初始化来对红色、蓝色司令部对象赋值,下面会继续说明。
2、类:司令部
class slb {
private:
string name; //是什么司令部,红色or蓝色
int live; //司令部总生命元
string ws[5]; //武士顺序名称
int wslive[5]; //武士对应生命值
int num[5] = { 0 }; //武士对应制造数量
int sum = 0; //总制造武士数量
int tag = 0; //标记,使得司令部能循环制造武士
public:
int flag = 1; //生命元不够退出标志
slb(string nname, int llive) { //构造函数初始化
name = nname; //名称初始化
live = llive; //总生命源初始化
if (name == "red") //分别从外部数组获取数据初始化对象的成员变量
{
for (int i = 0; i < 5; i++)
{
ws[i] = rws[i]; //武士名称
wslive[i] = rwsl[i]; //武士生命
}
}
else
{
for (int i = 0; i < 5; i++)
{
ws[i] = bws[i]; //武士名称
wslive[i] = bwsl[i]; //武士生命
}
}
}
void born() //武士出生
{
for (int i = tag; i < 5; i++)
if (wslive[i] <= live)
{
live -= wslive[i];
cout << setw(3) << setfill('0') << tim << ' ' << name //格式化输出时间
<< ' ' << ws[i] << ' ' << //输出武士名字
++sum << " born with strength " << wslive[i] << ',' //总数量、生命
<< ++num[i] << ' ' << ws[i] << " in " << name << //对应数量
" headquarter" << endl;
tag = (i + 1) % 5; //循环初始化
return;
}
//如果前面循环未执行则执行下面操作
tag = 0; //前面从tag到末尾的循环未找到,从头开始找
//下面代码与上面一样
for (int i = tag; i < 5; i++)
if (wslive[i] <= live)
{
live -= wslive[i];
cout << setw(3) << setfill('0') << tim << ' ' << name
<< ' ' << ws[i] << ' ' <<
++sum << " born with strength " << wslive[i] << ','
<< ++num[i] << ' ' << ws[i] << " in " << name
<< " headquarter" << endl;
tag = (i + 1) % 5;
return;
}
}
//生命元不够,输出语句,并flag置0
void destroy()
{
if (flag)
cout << setw(3) << setfill('0') << tim << ' ' << name
<< " headquarter stops making warriors" << endl;
flag = 0;
}
//是否生命元够制造武士
bool ifcontinue()
{
if (live < mmin) //所剩生命元比最小需要都小一定制造不出来
return 0;
return 1;
}
};
此类的说明在代码中已经体现了一部分,下面再对born函数(主要是tag)作进一步说明。
举个例子,在最开始制造时,由数组下标0处开出循环判断,假设在3处找到,tag后面做处理时取模结果仍为3。下面再进入时i从3开始到4未找到符合的,令tag为0,找前面的下标。
对于取模运算其实就是为了下标为4时(最后一个),那么下一个武士从第一个开始判断。
(tag+1)%5得到0,即可完成需要。
3.init()初始化
void init()
{
tim = 0;
mmin = 100000;
for (int i = 0; i < 5; i++)
for (int j = 0; j < 5; j++)
{
if (biao[i] == rws[j])
rwsl[j] = al[i];
if (biao[i] == bws[j])
bwsl[j] = al[i];
}
for (int i = 0; i < 5; i++)
mmin = min(al[i], mmin); //存储最小的生命值
}
每一次tim初始化为0, mmin令为最大值,保证取到最小值一定为武士的生命元。
双层循环,判断标准武士名等于司令部对应顺序的武士名,将生命元放入对应位置。
这样,前面所述4个数组
string rws[5] = { "iceman","lion","wolf","ninja","dragon" };
string bws[5] = { "lion","dragon","ninja","iceman","wolf" };
int rwsl[5]; //红色武士生命值
int bwsl[5]; //蓝色武士生命值
前两个分别为不同司令部对应武士名顺序,后两个存放对应生命值。
4、主函数
int main()
{
cin >> N;
for (int i = 1; i <= N; i++)
{
cin >> m; //生命值上限
for (int j = 0; j < 5; j++)
cin >> al[j]; //每种武士生命值
init(); //初始化
slb* red = new slb("red", m), * blue = new slb("blue", m);
//创建红蓝司令部两个对象,后面二者操作即可
cout << "Case:" << i << endl;
do
{
if (red->ifcontinue()) //如果能制造就制造
red->born();
else
red->destroy(); //不能就输出一次,然后该司令部不会再输出
if (blue->ifcontinue())
blue->born();
else blue->destroy();
tim++;
} while (red->ifcontinue() || blue->ifcontinue()); //只要有一个能输出就循环
//因为前面如果制造出来武士,其司令部生命源不够制造了,
//可能会跳出循环,但未进行destroy()操作,这里保证二者都能正常完成
red->destroy();
blue->destroy();
delete red, blue; //删除俩个对象
}
return 0;
}
此处说明已在代码体现,再说明一下循环外面的两个destroy(),如果循环内调用了,由于flag使得destroy()不会再次调用,外面调用也不会输出东西。
#include<iostream>
#include<iomanip>
#include<string.h>
using namespace std;
int N, m, tim; int al[5]; int mmin = 10005;
string biao[5] = { "dragon","ninja","iceman","lion","wolf" };
string rws[5] = { "iceman","lion","wolf","ninja","dragon" };
string bws[5] = { "lion","dragon","ninja","iceman","wolf" };
int rwsl[5]; //红色武士生命值
int bwsl[5]; //蓝色武士生命值
class slb {
private:
string name;
int live;
string ws[5]; //武士顺序名称
int wslive[5]; //对应生命值
int num[5] = { 0 };
int sum = 0;
int tag = 0;
public:
int flag = 1;
//int state = 1;
slb(string nname, int llive) {
name = nname;
live = llive;
if (name == "red")
{
for (int i = 0; i < 5; i++)
{
ws[i] = rws[i];
wslive[i] = rwsl[i];
}
}
else
{
for (int i = 0; i < 5; i++)
{
ws[i] = bws[i];
wslive[i] = bwsl[i];
}
}
}
void born()
{
for (int i = tag; i < 5; i++)
if (wslive[i] <= live)
{
live -= wslive[i];
cout << setw(3) << setfill('0') << tim << ' ' << name << ' ' << ws[i] << ' ' <<
++sum << " born with strength " << wslive[i] << ','
<< ++num[i] << ' ' << ws[i] << " in " << name << " headquarter" << endl;
tag = (i + 1) % 5;
return;
}
tag = 0;
for (int i = tag; i < 5; i++)
if (wslive[i] <= live)
{
live -= wslive[i];
cout << setw(3) << setfill('0') << tim << ' ' << name << ' ' << ws[i] << ' ' <<
++sum << " born with strength " << wslive[i] << ','
<< ++num[i] << ' ' << ws[i] << " in " << name << " headquarter" << endl;
tag = (i + 1) % 5;
return;
}
}
void destroy()
{
if (flag)
cout << setw(3) << setfill('0') << tim << ' ' << name
<< " headquarter stops making warriors" << endl;
flag = 0;
}
bool ifcontinue()
{
if (live < mmin)
return 0;
return 1;
}
};
void init()
{
tim = 0;
mmin = 100000;
for (int i = 0; i < 5; i++)
for (int j = 0; j < 5; j++)
{
if (biao[i] == rws[j])
rwsl[j] = al[i];
if (biao[i] == bws[j])
bwsl[j] = al[i];
}
for (int i = 0; i < 5; i++)
mmin = min(al[i], mmin); //存储最小的生命值
}
int main()
{
cin >> N;
for (int i = 1; i <= N; i++)
{
cin >> m; //生命值上限
for (int j = 0; j < 5; j++)
cin >> al[j]; //每种武士生命值
init();
slb* red = new slb("red", m), * blue = new slb("blue", m);
cout << "Case:" << i << endl;
do
{
if (red->ifcontinue())
red->born();
else
red->destroy();
if (blue->ifcontinue())
blue->born();
else blue->destroy();
tim++;
} while (red->ifcontinue() || blue->ifcontinue());
red->destroy();
blue->destroy();
delete red, blue;
}
return 0;
}