题解 P2482 【[SDOI2010]猪国杀】

_虹_

2018-12-17 17:57:06

Solution

疑似史上 ~~最易理解~~代码最长 猪国杀 听说某位蒟da蒻lao因为不会面向过程写了面向对象。~~我oi白学。~~ 除了上面的大佬们提到的坑点,加上几个我自己写的时候发现的注意点: 1. **无论锦囊牌是不是生效,出了就会触发献殷勤/表敌意。** 2. ** 跳身份很好处理,只要触发了献殷勤/表敌意,把自己的身份表明就好了。** 3. 猪都很耿直,能表明身份就表明身份。 4. 无懈可击是对被攻击的猪献殷勤/表敌意。 写完30分的时候过了一遍代码逻辑,总体应该还是挺清晰的,代码里也有些中英混杂的注释。~~所以不想额外加注释了。~~ 代码效率不高,也有几个凑活的地方,比如class_world::piglist应该是一个环状链表,再用一个数组做索引进行o(1)的查找和删除(world类外部持有list::iterator总觉得不太好) class_basic_pig::cardlist也应该是一个链表,然后我就全都vector解决了。。。。 应该没有什么隐蔽的错误。只是虽然我很尽力了,耦合貌似还是蛮高的。。。。。 开发规范本来就没有正经学习,现在也忘得很干净了。 但是程序中各种命名还是尽力保证可读性,试图去遵守一下命名规范的(虽然没成功吧)。~~不过后来改bug导致某些命名和其它命名不太一致。 大家谅解一下。~~ 虽然代码1000来行,不过可读性应该还行吧...~~(心虚)~~ **不想看代码建议直接看结尾,提供vs2015 project下载,观赏效果更佳。** ### 下面大量类继承,多态警告: ```cpp // luogu-judger-enable-o2 #include <vector> #include <queue> #include <list> #include <iostream> #include <cstdlib> using namespace std; enum enum_status { DEAD = 0, UNKNOW = 1, FRIEND = 2, ENEMY = 3, ETBE = 4 }; enum enum_card { BLOOD = 1, KILL = 2, MISS = 3, FIGHT = 4, N_ATK = 5, W_ATK = 6, J_DF = 7, ARM = 8 };//无懈可击是J_DF,这个鬼东西我是真不会起名了 enum enum_kind { MAIN_PIG = 1, FRIEND_PIG = 2, ENEMY_PIG = 3 }; #define reg register #define null NULL #define MAXBLOOD 4 struct Event; class class_basic_pig { public: enum_kind Kind; enum_status Status; bool Armed; int num;//数组下标 int Blood; vector<enum_card> CardList; class_basic_pig(const int _num, enum_kind _kind) :num(_num), Kind(_kind),Armed(false),Blood(MAXBLOOD),Status(UNKNOW){}; void N_Attack(); void W_Attack(); virtual void N_AttackBy(class_basic_pig*)=0; virtual void W_AttackBy(class_basic_pig*)=0; virtual void C_AttackBy(class_basic_pig*)=0; void StartFightWith(class_basic_pig*);//start to fight with ptr virtual const bool FightWith(class_basic_pig*)=0;//fight with ptr bool DropCard(enum_card);//return true if pig has this card to drop,or false if hasnt void Hurt();//pig is hurt,try to heal,updata pigs status //virtual void Updata();//updata pigs status //virtual void SpecialDefence();//if use special defence card virtual bool Usable(const enum_card&,bool&);//if the card usable//子类重载并且调用basic类的函数 virtual const bool IsEnemy(const enum_status&)=0;//判断是否为敌人 virtual void CheckAfterAttack(class_basic_pig* ptr) = 0;//造成伤害后结算 void Turn(); virtual void UseCard(enum_card)=0; virtual bool UseSpecialDefence(Event)=0;//true: used,false: didnt use virtual void UpdataIdentity() = 0; }; struct Event { class_basic_pig* source;//锦囊牌发出者 class_basic_pig* target;//锦囊牌接受者 bool Good;//true:献殷勤,false:表敌意 Event(class_basic_pig* s = null, class_basic_pig* t = null, bool b = false) :source(s), target(t), Good(b) {}; }; class class_world { public: vector<class_basic_pig*> PigList; queue<enum_card> CardPool; class_basic_pig* GetEnemy(int num, class_basic_pig* ptr); class_basic_pig* GetNext(int num); class_basic_pig* GetLast(int num); enum_card GetCard() { enum_card t = CardPool.front(); if (CardPool.size() > 1) { CardPool.pop(); } return t; } void EndGame(); void GameBegin(); bool CheckSpecialDefnece(Event);//if oridary event can happen,return true,else return false }World; class class_main_pig:public class_basic_pig { public: class_main_pig(const int _num):class_basic_pig(_num, MAIN_PIG){}; virtual void N_AttackBy(class_basic_pig*); virtual void W_AttackBy(class_basic_pig*); virtual void C_AttackBy(class_basic_pig*); virtual bool Usable(const enum_card&,bool&); virtual const bool IsEnemy(const enum_status&); virtual const bool FightWith(class_basic_pig*); virtual void CheckAfterAttack(class_basic_pig*); virtual void UseCard(enum_card); virtual bool UseSpecialDefence(Event); virtual void UpdataIdentity() {}; }; class class_friend_pig :public class_basic_pig { public: class_friend_pig(const int _num) :class_basic_pig(_num, FRIEND_PIG) {}; virtual void N_AttackBy(class_basic_pig*); virtual void W_AttackBy(class_basic_pig*); virtual void C_AttackBy(class_basic_pig*); virtual bool Usable(const enum_card&, bool&); virtual const bool IsEnemy(const enum_status&); virtual const bool FightWith(class_basic_pig*); virtual void CheckAfterAttack(class_basic_pig*); virtual void UseCard(enum_card); virtual bool UseSpecialDefence(Event); virtual void UpdataIdentity(); }; class class_enemy_pig :public class_basic_pig { public: class_enemy_pig(const int _num) :class_basic_pig(_num, ENEMY_PIG) {}; virtual void N_AttackBy(class_basic_pig*); virtual void W_AttackBy(class_basic_pig*); virtual void C_AttackBy(class_basic_pig*); virtual bool Usable(const enum_card&, bool&); virtual const bool IsEnemy(const enum_status&); virtual const bool FightWith(class_basic_pig*); virtual void CheckAfterAttack(class_basic_pig*); virtual void UseCard(enum_card); virtual bool UseSpecialDefence(Event); virtual void UpdataIdentity(); }; char un_translate(enum_card card) { char ch; switch (card) { case BLOOD: ch = 'P'; break; case KILL: ch = 'K'; break; case MISS: ch = 'D'; break; case FIGHT: ch = 'F'; break; case N_ATK: ch = 'N'; break; case W_ATK: ch = 'W'; break; case J_DF: ch = 'J'; break; case ARM: ch = 'Z'; break; } return ch; } void class_basic_pig::N_Attack() { class_basic_pig* ptr = null; int pos = num; while ((ptr = World.GetNext(pos)) && ptr->num!=num ) { pos = ptr->num; ptr->N_AttackBy(this); CheckAfterAttack(ptr); } } void class_basic_pig::W_Attack() { class_basic_pig* ptr = null; int pos = num; while ((ptr = World.GetNext(pos)) && ptr->num != num) { pos = ptr->num; ptr->W_AttackBy(this); CheckAfterAttack(ptr); } } bool class_basic_pig::DropCard(enum_card c) { int s = CardList.size(); for (reg int i = 0; i < s; ++i) { if (CardList[i] == c) { CardList.erase(CardList.begin()+i); return true; } } return false; } bool class_basic_pig::Usable(const enum_card& c,bool& tag) { if ((c == BLOOD&&Blood < MAXBLOOD) || c == N_ATK || c == W_ATK || c == ARM) return true; class_basic_pig* ptr = World.GetNext(num);//杀 if ((Armed || (!tag)) && c == KILL && IsEnemy(ptr->Status)) { tag = true; return true; } return false; } void class_basic_pig::StartFightWith(class_basic_pig* ptr) { UpdataIdentity(); if (!World.CheckSpecialDefnece(Event(this, ptr, false))) { return; } int i = 1; while (i % 2 ? ptr->FightWith(this) : FightWith(ptr)) { ++i;//do nothing } if (i % 2)//ptr hurt { CheckAfterAttack(ptr); } else { ptr->CheckAfterAttack(this); } } void class_basic_pig::Hurt() { --Blood; if (Blood < 1) { while (Blood < 1 && DropCard(BLOOD)) ++Blood;//heal if (Blood < 1) { Status = DEAD; if (Kind == MAIN_PIG) { World.EndGame(); } bool tag = false; for (reg int j = 0; j < World.PigList.size(); ++j) { if (World.PigList[j]->Kind == ENEMY_PIG&&World.PigList[j]->Status != DEAD) { tag = true; } } if (!tag) { World.EndGame(); } } } } void class_basic_pig::Turn() { CardList.push_back(World.GetCard()); CardList.push_back(World.GetCard()); bool tag = true; bool kill_tag = false; while (tag&&Status!=DEAD) { tag = false; for (reg int i = 0; i < CardList.size(); ++i) { if (Usable(CardList[i], kill_tag)) { tag = true; UseCard(CardList[i]); break; } } } } class_basic_pig* class_world::GetEnemy(int num, class_basic_pig* ptr)// (now pos,check func) { int tot = PigList.size(); for (reg int i = 0; i < tot; ++i) { if (ptr->IsEnemy(PigList[(++num) % tot]->Status))//pig is able to attack because of the status { return PigList[num%tot]; } } return null; } class_basic_pig* class_world::GetNext(int num)//now pos { int tot = PigList.size(); for (reg int i = 0; i < tot; ++i) { if (PigList[(++num) % tot]->Status != DEAD)//pig is alive { return PigList[num % tot]; } } return null; } class_basic_pig* class_world::GetLast(int num)//now pos { int tot = PigList.size(); for (reg int i = 0; i < tot; ++i) { if (PigList[(tot + (--num)) % tot]->Status != DEAD)//pig is alive { return PigList[(tot + (num)) % tot]; } } return null; } void class_world::EndGame() { if (PigList[0]->Status == DEAD) cout << "FP" << endl; else cout << "MP" << endl; for (reg int i = 0; i < PigList.size(); ++i) { if (PigList[i]->Status == DEAD) { cout << "DEAD" << endl; } else { for (reg int j = 0; j < PigList[i]->CardList.size(); ++j) { cout << un_translate(PigList[i]->CardList[j]) << ' '; } cout << endl; } } exit(-1);//i think this might stop you from AC on luogu if you just copy the code. } void class_world::GameBegin() { int tot=PigList.size(); for (reg int i = 0;; ++i) { i = i%tot; if(PigList[i]->Status!=DEAD) PigList[i]->Turn(); } } bool class_world::CheckSpecialDefnece(Event e)//if oridary event can happen,return true,else return false { class_basic_pig* ptr = e.source; if (!ptr) return true; int num = ptr->num; do { if (ptr->UseSpecialDefence(e)) { ptr->UpdataIdentity(); if (CheckSpecialDefnece(Event(ptr, e.target, !e.Good)))//happend { return false; } return true; } } while ((ptr = GetNext(ptr->num))->num != num); return true; } void class_main_pig::N_AttackBy(class_basic_pig* ptr) { if (!World.CheckSpecialDefnece(Event(ptr, this, false))) { return; } if (DropCard(KILL)) { return;//丢弃杀 } else { if (ptr->Status == UNKNOW) ptr->Status = ETBE; Hurt(); } } void class_main_pig::W_AttackBy(class_basic_pig* ptr) { if (!World.CheckSpecialDefnece(Event(ptr, this, false))) { return; } if (DropCard(MISS)) { return;//丢弃闪 } else { if (ptr->Status == UNKNOW) ptr->Status = ETBE; Hurt(); } } bool class_main_pig::Usable(const enum_card& c,bool& tag)//check if this card usable { if (class_basic_pig::Usable(c,tag)) { return true; } //ptr = World.GetEnemy(num, ((const bool (class_basic_pig::*)(const enum_status&))this->IsEnemy)); if (c == FIGHT) { if (World.GetEnemy(num, this))//have enemy return true; } return false; } const bool class_main_pig::IsEnemy(const enum_status& s) { return s == ENEMY || s == ETBE; } void class_main_pig::C_AttackBy(class_basic_pig* ptr) { ptr->Status = ENEMY; if (DropCard(MISS)) { ;//丢弃闪 } else { Hurt(); } } const bool class_main_pig::FightWith(class_basic_pig* ptr)//fight with ptr { if (DropCard(KILL)) { return true; } else { Hurt(); return false; } } void class_main_pig::CheckAfterAttack(class_basic_pig* ptr)//胜者结算 { if(ptr->Status == DEAD) { if (ptr->Kind == FRIEND_PIG) { CardList.clear(); Armed = false; } else { CardList.push_back(World.GetCard()); CardList.push_back(World.GetCard()); CardList.push_back(World.GetCard()); } } } void class_main_pig::UseCard(enum_card c) { DropCard(c); class_basic_pig* ptr; switch (c) { case KILL: ptr = World.GetNext(num); ptr->C_AttackBy(this); CheckAfterAttack(ptr); break; case BLOOD: ++Blood; break; case N_ATK: N_Attack(); break; case W_ATK: W_Attack(); break; case ARM: Armed = true; break; case FIGHT: ptr=World.GetEnemy(num, this); StartFightWith(ptr); break; } } bool class_main_pig::UseSpecialDefence(Event e) { bool tag = false; if (e.target->Status == FRIEND) { if (!e.Good)//event表示对友军表敌意 { tag= true;//使用无懈可击献殷勤 } } if (e.target->Status == ENEMY) { if (e.Good)//对敌军献殷勤 { tag= true;//表敌意 } } if (tag) { tag = DropCard(J_DF); } return tag; } ////////////////////////////////////////////////////////////////////// void class_friend_pig::N_AttackBy(class_basic_pig* ptr) { if (!World.CheckSpecialDefnece(Event(ptr, this, false))) { return; } if (DropCard(KILL)) { return;//丢弃杀 } else { Hurt(); } } void class_friend_pig::W_AttackBy(class_basic_pig* ptr) { if (!World.CheckSpecialDefnece(Event(ptr, this, false))) { return; } if (DropCard(MISS)) { return;//丢弃闪 } else { Hurt(); } } bool class_friend_pig::Usable(const enum_card& c, bool& tag)//check if this card usable { if (class_basic_pig::Usable(c, tag)) { return true; } //ptr = World.GetEnemy(num, ((const bool (class_basic_pig::*)(const enum_status&))this->IsEnemy)); if (c == FIGHT) { if (World.GetEnemy(num,this))//have enemy return true; } return false; } const bool class_friend_pig::IsEnemy(const enum_status& s) { return s == ENEMY; } void class_friend_pig::C_AttackBy(class_basic_pig* ptr) { if (ptr->Kind == MAIN_PIG)// ; else ptr->Status = ENEMY; if (DropCard(MISS)) { ;//丢弃闪 } else { Hurt(); } } const bool class_friend_pig::FightWith(class_basic_pig* ptr)//fight with ptr { if (ptr->Kind == MAIN_PIG) { Hurt(); return false; } if (DropCard(KILL)) { return true; } else { Hurt(); return false; } return false; } void class_friend_pig::CheckAfterAttack(class_basic_pig* ptr)//胜者(攻击者)结算 { if (ptr->Status == DEAD) { if(ptr->Kind==ENEMY_PIG) { CardList.push_back(World.GetCard()); CardList.push_back(World.GetCard()); CardList.push_back(World.GetCard()); } } } void class_friend_pig::UseCard(enum_card c) { DropCard(c); class_basic_pig* ptr; switch (c) { case KILL: ptr = World.GetNext(num); ptr->C_AttackBy(this); CheckAfterAttack(ptr); break; case BLOOD: ++Blood; break; case N_ATK: N_Attack(); break; case W_ATK: W_Attack(); break; case ARM: Armed = true; break; case FIGHT: ptr = World.GetEnemy(num, this); StartFightWith(ptr); break; } } bool class_friend_pig::UseSpecialDefence(Event e) { bool tag = false; if (e.target->Status == FRIEND) { if (!e.Good)//event表示对友军表敌意 { tag= true;//使用无懈可击献殷勤 } } if (e.target->Status == ENEMY) { if (e.Good)//对敌军献殷勤 { tag= true;//表敌意 } } if (tag) { tag = DropCard(J_DF); } return tag; } void class_friend_pig::UpdataIdentity() { Status = FRIEND; } ///////////////////////////////////////////////////////////////////// void class_enemy_pig::N_AttackBy(class_basic_pig* ptr) { if (!World.CheckSpecialDefnece(Event(ptr, this, false))) { return; } if (DropCard(KILL)) { return;//丢弃杀 } else { Hurt(); } } void class_enemy_pig::W_AttackBy(class_basic_pig* ptr) { if (!World.CheckSpecialDefnece(Event(ptr, this, false))) { return; } if (DropCard(MISS)) { return;//丢弃闪 } else { Hurt(); } } bool class_enemy_pig::Usable(const enum_card& c, bool& tag)//check if this card usable { if (class_basic_pig::Usable(c, tag)) { return true; } //ptr = World.GetEnemy(num, ((const bool (class_basic_pig::*)(const enum_status&))this->IsEnemy)); if (c == FIGHT) { return true; } return false; } const bool class_enemy_pig::IsEnemy(const enum_status& s) { return s == FRIEND; } void class_enemy_pig::C_AttackBy(class_basic_pig* ptr) { ptr->Status = FRIEND; if (DropCard(MISS)) { ;//丢弃闪 } else { Hurt(); } } const bool class_enemy_pig::FightWith(class_basic_pig* ptr)//fight with ptr { if (DropCard(KILL)) { return true; } else { Hurt(); return false; } return false; } void class_enemy_pig::CheckAfterAttack(class_basic_pig* ptr)//胜者结算 { if (ptr->Status == DEAD) { if (ptr->Kind == ENEMY_PIG) { CardList.push_back(World.GetCard()); CardList.push_back(World.GetCard()); CardList.push_back(World.GetCard()); } } } void class_enemy_pig::UseCard(enum_card c) { DropCard(c); class_basic_pig* ptr; switch (c) { case KILL: ptr = World.GetNext(num); ptr-> C_AttackBy(this); CheckAfterAttack(ptr); break; case BLOOD: ++Blood; break; case N_ATK: N_Attack(); break; case W_ATK: W_Attack(); break; case ARM: Armed = true; break; case FIGHT: ptr = World.PigList[0];//主猪 StartFightWith(ptr); break; } } bool class_enemy_pig::UseSpecialDefence(Event e) { bool tag = false; if (e.target->Status == ENEMY) { if (!e.Good)//event表示对友军表敌意 { tag= true;//使用无懈可击献殷勤 } } if (e.target->Status == FRIEND) { if (e.Good)//对敌军献殷勤 { tag= true;//表敌意 } } if (tag) { tag = DropCard(J_DF); } return tag; } void class_enemy_pig::UpdataIdentity() { Status = ENEMY; } enum_card translate(char ch) { enum_card card; switch (ch) { case 'P': card = BLOOD; break; case 'K': card = KILL; break; case 'D': card = MISS; break; case 'F': card = FIGHT; break; case 'N': card = N_ATK; break; case 'W': card = W_ATK; break; case 'J': card = J_DF; break; case 'Z': card = ARM; break; } return card; } int main() { int n, m; char ch; cin >> n >> m; class_basic_pig* ptr; for (reg int i = 0; i < n; ++i) { cin >> ch; switch (ch) { case 'M': ptr = new class_main_pig(i); break; case 'Z': ptr = new class_friend_pig(i); break; case 'F': ptr = new class_enemy_pig(i); break; } World.PigList.push_back(ptr); cin >> ch; for (reg int j = 0; j < 4; ++j) { cin >> ch; ptr->CardList.push_back(translate(ch)); } } World.PigList[0]->Status = FRIEND; for (reg int i = 0; i < m; ++i) { cin >> ch; World.CardPool.push(translate(ch)); } World.GameBegin(); return 0; } ``` 刚刚上传工程才发现文件夹只有10几mb大,印象中vs一个工程100多mb的样子啊。。。。 **分享链接中,测试数据来自LOJ。** **vs2015 project下载:** [度盘链接](https://pan.baidu.com/s/1eoVcX2Zz1LkBpbVHyGZKxA) 提取码:6nbh 希望管理大大给个通过。