个人技术分享

课程:北京大学程序设计与算法(三)     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;
}