[BZOJ 1972][Sdoi2010]猪国杀

1972: [Sdoi2010]猪国杀

Time Limit: 1 Sec  Memory Limit: 64 MB
Submit: 364  Solved: 204
[Submit][Status][Discuss]

Description

概述

 
 
《猪国杀》是一种多猪牌类回合制游戏,一共有三种角色:主猪,忠猪,反猪。
 
 
每局游戏主猪有且只有一只,忠猪和反猪可以有多只,每只猪扮演一种角色。
 
 
游戏目的
 
 
主猪(MP):自己存活的情况下消灭所有的反猪。
 
 
忠猪(ZP):不惜一切保护主猪,胜利条件与主猪相同。
 
 
反猪(AP):杀死主猪。
 
 
游戏过程
 
 
游戏开始时候,每个玩家手里都会有 4 张牌,且体力上限和初始体力都是 4 。
 
 
开始游戏时,从主猪开始,按照逆时针方向(数据中就是按照编号从 1, 2, 3...n, 1... 的顺序)依次行动。
 
 
每个玩家自己的回合可以分为 4 个阶段
 
 
摸牌阶段
 
 
从牌堆顶部摸两张牌,依次放到手牌的最右边。
 
 
出牌阶段
 
 
你可以使用 0 张到任意张牌,每次使用牌的时候都使用最靠左的能够使用的牌。
 
 
当然,要满足如下规则
 
 
如果没有猪哥连弩,每个出牌阶段只能使用一次“杀”来攻击。
 
 
任何牌被使用后被弃置(武器是装备上)。
 
 
被弃置的牌以后都不能再用,即与游戏无关。
 
 
各种牌介绍
 
 
每张手牌用一个字母表示,字母代表牌的种类。
 
 
基本牌
 
 
『桃(P)』
 
 
在自己的回合内,如果自己的体力值不等于体力上限,那么使用一个桃可以为自己补充一点体力;否则不能使用桃。
 
 
桃只能对自己使用。
 
 
在自己的回合外,如果自己的血变为 0 或者更低,那么也可以使用。
 
 
『杀(K)』
 
 
在自己的回合内,对攻击范围内除自己以外的一名角色使用。
 
 
如果没有被『闪』抵消,则造成 1 点伤害。
 
 
无论有无武器,杀的攻击范围都是 1。
 
 
『闪(D)』
 
 
当你受到杀的攻击时,可以弃置一张闪来抵消杀的效果。
 
 
锦囊牌
 
 
『决斗(F)』
 
 
出牌阶段,对除自己以外任意一名角色使用,由目标角色先开始,自己和目标角色轮流弃置一张杀,首先没有杀可弃的一方受到1点伤害,另一方视为此伤害的来源。
 
 
『南猪入侵(N)』
 
 
出牌阶段,对除你以外所有角色使用,按逆时针顺序从使用者下家开始依次结算,除非弃置一张杀,否则受到1点伤害。
 
 
『万箭齐发(W)』
 
 
和南猪入侵类似,不过要弃置的不是杀而是闪。
 
 
『无懈可击(J)』
 
 
在目标锦囊生效前抵消其效果。
 
 
每次有一张锦囊即将生效时,从使用这张锦囊的猪开始,按照逆时针顺序,依次得到使用无懈可击的机会。
 
 
效果
 
 
用于决斗时,决斗无效并弃置。
 
 
用于南猪入侵或万箭齐发时,当结算到某个角色时才能使用,当前角色不需弃置牌并且不会受到伤害(仅对一个角色产生效果)。
 
 
用于无懈可击时,成为目标的无懈可击被无效。
 
 
装备牌
 
 
『猪哥连弩(Z)』
 
 
武器,攻击范围 1,出牌阶段你可以使用任意张杀。
 
 
同一时刻最多只能装一个武器。
 
 
如果先前已经有了一把武器,那么之后再装武器的话,会弃置以前的武器来装现在的武器。
 
 
特殊事件及概念解释
 
 
伤害来源
 
 
杀、南猪入

Input

第一行包含两个正整数n(2 <= n <= 10) 和m( m <= 2000),分别代表玩家数和牌堆中牌的数量。数据保证牌的数量够用。 接下来n行,每行5个字符串,依次表示对第i只猪的角色和初始4张手牌描述。编号为1的肯定是主猪。 再接下来一行,一共m个字符串,按照从牌堆顶部到牌堆底部的顺序描述每张牌。 所有的相邻的两个字符串都严格用1个空格隔开,行尾没有多余空格。

Output

输出数据第一行包含一个字符串代表游戏结果。如果是主猪胜利,那么输出“MP”,否则输出“FP”。数据保证游戏总会结束。 接下来n行,第i行是对第i只猪的手牌描述(注意只需要输出手牌),按照手牌从左往右的顺序输出,相邻两张牌用一个空格隔开,行末尾没有多余空格。如果这只猪已阵亡,那么只要输出“DEAD”即可。注意如果要输出手牌而没有手牌的话,那么只需输出一个空行。

Sample Input

3 10
MP D D F F
ZP N N N D
FP J J J J
F F D D J J F F K D

Sample Output

FP
DEAD
DEAD
J J J J J D

HINT

 

样例1说明:第一回合主猪没有目标可以表敌意;接下来忠猪使用了3张南猪入侵,主猪掉了3点体力,并认为该角色为类反猪,3号角色尽管手里有无懈可击,但是因为自己未表明身份,所以同样不能对自己用,乖乖掉3点体力;下一回合反猪无牌可出;接下来主猪对着类反猪爆发,使用4张决斗,忠猪死亡,结果主猪弃掉所有牌;下来反猪摸到一张杀直接杀死主猪获胜。 数据说明:一共20组测试数据,每个点5分。10%的数据没有锦囊牌,另外20%的数据没有无懈可击。

 

Source

麻麻我要把这个出题人挂起来裱QAQ!

题解

不想多说啥, 就是个大模拟(难以置信的是这是个省选题?!)

说一下我碰到的几个辣鸡坑爹细节好了

1.抽完牌要强行接着抽最后一张

2.清空主公的牌的时候, 首先注意连弩标记也要重置, 其次还得注意牌面迭代器QAQ(2个点RE到死...)

3.无懈可击在AOE下只对一人有效, 不能解决掉整个锦囊

4.无懈可击的遍历判定只有第一个打出无懈可击的玩家有无懈可击的权利, 如果这张无懈可击被后续的无懈可击无效掉也不会继续给后面的玩家机会

5.BZOJ辣鸡题面只截了一半吃枣药丸...可读题面

6.反贼的所有决斗无条件扔给主公

7.杀/决斗/无懈可击都是跳身份的标志, 而且只能对显露身份的玩家使用

然后就是自己的思博错误: 南蛮入侵和万箭齐发的时候如果被无懈可击掉的话判定点不会继续迭代而会消耗掉所有无懈可击QAQ

参考代码

GitHub

  1 #include <list>
  2 #include <vector>
  3 #include <cstdio>
  4 #include <cstring>
  5 #include <iostream>
  6 #include <algorithm>
  7 
  8 struct Card;
  9 
 10 struct Pig{
 11     Pig(int);
 12     int ID;
 13     int HP;
 14     bool LN;
 15     bool JMP,APL;
 16     bool MP,AP,ZP;
 17     Pig* prev;
 18     Pig* next;
 19     void Jump();
 20     void Clear();
 21     void Round();
 22     void Print();
 23     void Arrows();
 24     void SetAPL();
 25     void Die(Pig*);
 26     void Invasion();
 27     void GetCard(int);
 28     void GetHurt(Pig*);
 29     bool Kill();
 30     bool TryDuel();
 31     bool UseKill();
 32     bool UseMiss();
 33     bool UsePeach();
 34     bool JFor(bool);
 35     bool Duel(Pig*);
 36     bool UseCard(char);
 37     bool FindJBecauseOf(Pig*);
 38     std::list<Card*> cards;
 39 };
 40 
 41 struct Card{
 42     Card();
 43     char type;
 44     bool Act(Pig*);
 45 };
 46 
 47 int n;
 48 int m;
 49 int APs;
 50 bool END;
 51 char last;
 52 char buf[5];
 53 std::vector<Pig*> v;
 54 
 55 void Initialize();
 56 
 57 int main(){
 58     Initialize();
 59     Pig* root=v[0];
 60     while(!END){
 61         root->Round();
 62         root=root->next;
 63     }
 64     if(APs==0)
 65         puts("MP");
 66     else
 67         puts("FP");
 68     for(std::vector<Pig*>::iterator i=v.begin();i!=v.end();++i)
 69         (*i)->Print();
 70     return 0;
 71 }
 72 
 73 bool Pig::Kill(){
 74     if(this->AP){
 75         if(this->next==v[0]||(this->next->ZP&&this->next->JMP)){
 76             this->JMP=true;
 77             if(!this->next->UseMiss())
 78                 this->next->GetHurt(this);
 79             return true;
 80         }
 81     }
 82     else if(this->MP){
 83         if(this->next->JMP){
 84             if(this->next->AP){
 85                 if(!this->next->UseMiss())
 86                     this->next->GetHurt(this);
 87                 return true;
 88             }
 89         }
 90         else{
 91             if(this->next->APL){
 92                 if(!this->next->UseMiss())
 93                     this->next->GetHurt(this);
 94                 return true;
 95             }
 96         }
 97     }
 98     else if(this->ZP){
 99         if(this->next->AP&&this->next->JMP){
100             if(!this->next->UseMiss())
101                 this->next->GetHurt(this);
102             return true;
103         }
104     }
105     return false;
106 }
107 
108 bool Pig::TryDuel(){
109     if(this->AP){
110         this->JMP=true;
111         if(!v[0]->FindJBecauseOf(this)){
112             if(v[0]->Duel(this))
113                 v[0]->GetHurt(this);
114             else
115                 this->GetHurt(v[0]);
116         }
117         return true;
118     }
119     else if(this->MP){
120         Pig* root=this->next;
121         while(root!=this){
122             if((root->AP&&root->JMP)||(root->APL&&!root->JMP)){
123                 if(!root->FindJBecauseOf(this)){
124                     if(root->Duel(this))
125                         root->GetHurt(this);
126                     else
127                         this->GetHurt(root);
128                 }
129                 return true;
130             }
131             root=root->next;
132         }
133     }
134     else if(this->ZP){
135         Pig* root=this->next;
136         while(root!=this){
137             if(root->AP&&root->JMP){
138                 this->JMP=true;
139                 if(!root->FindJBecauseOf(this)){
140                     if(root->Duel(this))
141                         root->GetHurt(this);
142                     else
143                         this->GetHurt(root);
144                 }
145                 return true;
146             }
147             root=root->next;
148         }
149     }
150     return 0;
151 }
152 
153 bool Pig::Duel(Pig* source){
154     if(this->ZP&&source->MP)
155         return true;
156     else{
157         while(true){
158             if(!this->UseKill())
159                 return true;
160             if(!source->UseKill())
161                 return false;
162         }
163     }
164 }
165 
166 void Pig::Round(){
167     this->GetCard(2);
168     bool Kused=false;
169     bool flag=false;
170     for(std::list<Card*>::iterator i=this->cards.begin();(!this->cards.empty())&&i!=this->cards.end();flag?i:++i){
171         flag=false;
172         if(END||this->HP==0)
173             break;
174         if((*i)->type=='P'&&this->HP<4){
175             this->HP++;
176             if(!this->cards.empty())
177                 this->cards.erase(i);
178             i=this->cards.begin();
179             flag=true;
180         }
181         else if((*i)->type=='N'){
182             this->Invasion();
183             if(!this->cards.empty())
184                 this->cards.erase(i);
185             i=this->cards.begin();
186             flag=true;
187         }
188         else if((*i)->type=='W'){
189             this->Arrows();
190             if(!this->cards.empty())
191                 this->cards.erase(i);
192             i=this->cards.begin();
193             flag=true;
194         }
195         else if((*i)->type=='K'&&(!Kused||this->LN)){
196             if(this->Kill()){
197                 if(!this->cards.empty())
198                     this->cards.erase(i);
199                 i=this->cards.begin();
200                 flag=true;
201                 Kused=true;
202             }
203         }
204         else if((*i)->type=='F'){
205             if(this->TryDuel()){
206                 if(!this->cards.empty())
207                     this->cards.erase(i);
208                 i=this->cards.begin();
209                 flag=true;
210             }
211         }
212         else if((*i)->type=='Z'){
213             if(!this->cards.empty())
214                 this->cards.erase(i);
215             i=this->cards.begin();
216             flag=true;
217             if(this->LN==false){
218                 this->LN=true;
219             }
220         }
221     }
222 }
223 
224 bool Pig::JFor(bool AP){
225     Pig* root=this;
226     do{
227         if(root->AP==AP){
228             if(root->UseCard('J')){
229                 root->JMP=true;
230                 return !root->JFor(!AP);
231             }
232         }
233         root=root->next;
234     }while(root!=this);
235     return false;
236 }
237 
238 bool Pig::FindJBecauseOf(Pig* source){
239     if((!this->JMP)&&(!this->MP))
240         return false;
241     else{
242         return source->JFor(this->AP);
243     }
244 }
245 
246 void Pig::GetHurt(Pig* source){
247     this->HP--;
248     if(this->HP<=0){
249         if(this->UsePeach())
250             this->HP++;
251         else
252             this->Die(source);
253     }
254 }
255 
256 void Pig::Clear(){
257     this->LN=false;
258     this->cards.clear();
259 }
260 
261 void Pig::Die(Pig* source){
262     this->prev->next=this->next;
263     this->next->prev=this->prev;
264     if(this->MP)
265         END=true;
266     else if(this->AP){
267         APs--;
268         if(APs<=0){
269             END=true;
270             return;
271         }
272         source->GetCard(3);
273     }
274     else if(this->ZP&&source->MP){
275         source->Clear();
276     }
277 }
278 
279 bool Pig::UseKill(){
280     return this->UseCard('K');
281 }
282 
283 bool Pig::UseMiss(){
284     return this->UseCard('D');
285 }
286 
287 bool Pig::UsePeach(){
288     return this->UseCard('P');
289 }
290 
291 void Pig::SetAPL(){
292     if(!this->JMP)
293         this->APL=true;
294 }
295 
296 bool Pig::UseCard(char ch){
297     for(std::list<Card*>::iterator i=this->cards.begin();i!=this->cards.end();++i){
298         if((*i)->type==ch){
299             this->cards.erase(i);
300             return true;
301         }
302     }
303     return false;
304 }
305 
306 void Initialize(){
307     scanf("%d%d",&n,&m);
308     m+=4*n;
309     for(int i=0;i<n;i++)
310         v.push_back(new Pig(i));
311     v[n-1]->next=v[0];
312     v[0]->prev=v[n-1];
313     for(int i=1;i<n;i++){
314         v[i-1]->next=v[i];
315         v[i]->prev=v[i-1];
316     }
317     if(APs==0)
318         END=true;
319 }
320 
321 Pig::Pig(int ID){
322     this->ID=ID;
323     this->LN=false;
324     this->JMP=this->APL=false;
325     this->AP=this->ZP=this->MP=false;
326     this->HP=4;
327     scanf("%s",buf);
328     if(*buf=='M')
329         this->MP=true;
330     else if(*buf=='Z')
331         this->ZP=true;
332     else
333         this->AP=true;
334     this->GetCard(4);
335     if(this->AP)
336         APs++;
337 }
338 
339 Card::Card(){
340     if(m>0){
341         scanf("%s",buf);
342         this->type=*buf;
343         last=this->type;
344         m--;
345     }
346     else
347         this->type=last;
348 }
349 
350 void Pig::Arrows(){
351     Pig* root=this->next;
352     while(root!=this){
353         if(root->FindJBecauseOf(this)){
354             root=root->next;// QAQ
355             continue;
356         }
357         if(!root->UseMiss()){
358             if(root->MP)
359                 this->SetAPL();
360             root->GetHurt(this);
361         }
362         if(END)
363             return;
364         root=root->next;
365     }
366 }
367 
368 void Pig::Invasion(){
369     Pig* root=this->next;
370     while(root!=this){
371         if(root->FindJBecauseOf(this)){
372             root=root->next;// QAQ
373             continue;
374         }
375         if(!root->UseKill()){
376             if(root->MP)
377                 this->SetAPL();
378             root->GetHurt(this);
379         }
380         if(END)
381             return;
382         root=root->next;
383     }
384 }
385 
386 void Pig::GetCard(int cnt){
387     while(cnt--)
388         this->cards.push_back(new Card());
389 }
390 
391 void Pig::Print(){
392     if(this->HP<=0)
393         puts("DEAD");
394     else{
395         while(!this->cards.empty()){
396             putchar(this->cards.front()->type);
397             this->cards.pop_front();
398             if(!this->cards.empty())
399                 putchar(' ');
400         }
401         putchar('\n');
402     }
403 }
Backup

(补图了补图了)

 

posted @ 2017-10-10 16:21  rvalue  阅读(720)  评论(0编辑  收藏  举报