CCF认证2016093-炉石传说
这道题应该是到目前为止我做过的最简单的第三题。本题没有什么复杂的算法和数据结构的设计,只需要根据要求自定义数据结构即可。我的思路是先设计随从类型,其属性包括攻击力和生命值。然后再设计英雄类型,其属性包括生命值和随从链表。召唤随从和攻击的操作进而变成了链表的操作。操作格式的判断可以使用正则表达式。
具体代码如下:
#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>>来存放英雄和该英雄的随从。这样英雄的位置自然就成了哨兵,不必再像代码中那样再插入一个无关结点。而且在攻击操作时也可以将对随从和对英雄的攻击操作统一。