这道题应该是到目前为止我做过的最简单的第三题。本题没有什么复杂的算法和数据结构的设计,只需要根据要求自定义数据结构即可。我的思路是先设计随从类型,其属性包括攻击力和生命值。然后再设计英雄类型,其属性包括生命值和随从链表。召唤随从和攻击的操作进而变成了链表的操作。操作格式的判断可以使用正则表达式。
具体代码如下:
#include <iostream>
#include <list>
#include <vector>
#include <regex>
using namespace std;
typedef struct SUMMON //随从
{
int attack;
int health;
SUMMON(int a, int h) :attack(a), health(h) {}
}SUMMON;
typedef struct HERO //英雄
{
int health = 30;
list<SUMMON> summons;
}HERO;
int main()
{
//FILE *stream;
//freopen_s(&stream, "data.txt", "r", stdin);
int n;
cin >> n;
getchar();
vector<HERO> h(2); //双方玩家,h[0]和h[1]分别代表先手和后手
h[0].summons.push_back(SUMMON(INT_MAX, INT_MAX)); //插入一个无关的结点方便后续的定位
h[1].summons.push_back(SUMMON(INT_MAX, INT_MAX));
int cur = 0; //当前下达命令的玩家编号,从先手开始
regex pa("attack ([\\d]+) ([\\d]+)");
regex ps("summon ([\\d]+) ([\\d]+) ([\\d]+)");
regex pe("end");
smatch result;
while(n--)
{
string cmd;
getline(cin, cmd);
if(regex_match(cmd, result, pe)) cur = (cur + 1) % 2; //回合结束
else if(regex_match(cmd, result, ps)) //召唤随从
{
int pos = stoi(result[1]), attack = stoi(result[2]), health = stoi(result[3]);
SUMMON s(attack, health);
auto point = h[cur].summons.begin();
for(; pos > 0; pos--)
point++;
h[cur].summons.insert(point, s);
}
else if(regex_match(cmd, result, pa)) //攻击
{
int enemy = (cur + 1) % 2;
int poscur = stoi(result[1]), posenemy = stoi(result[2]); //攻防位置
if(posenemy != 0) //攻击随从
{
auto pointa = h[cur].summons.begin();
auto pointb = h[enemy].summons.begin();
for(; poscur > 0; poscur--) pointa++;
for(; posenemy > 0; posenemy--) pointb++;
(*pointa).health -= (*pointb).attack;
(*pointb).health -= (*pointa).attack;
if((*pointa).health <= 0) h[cur].summons.erase(pointa);
if((*pointb).health <= 0) h[enemy].summons.erase(pointb);
}
else //攻击英雄
{
auto pointa = h[cur].summons.begin();
for(; poscur > 0; poscur--) pointa++;
h[enemy].health -= (*pointa).attack;
}
}
}
if(h[0].health > 0 && h[1].health > 0) cout << 0 << endl;
else if(h[0].health > 0) cout << 1 << endl;
else if(h[1].health > 0) cout << -1 << endl;
for(auto e : h)
{
cout << e.health << endl;
cout << e.summons.size() - 1 << ' ';
auto iter = e.summons.begin();
iter++;
while(iter != e.summons.end())
{
cout << (*iter).health << ' ';
iter++;
}
cout << endl;
}
//fclose(stream);
return 0;
}
实际上代码还可以进一步优化,那就是将英雄和随从统一看待,用一个vector<pair<int,int>>来存放英雄和该英雄的随从。这样英雄的位置自然就成了哨兵,不必再像代码中那样再插入一个无关结点。而且在攻击操作时也可以将对随从和对英雄的攻击操作统一。