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 DSample Output
FP
DEAD
DEAD
J J J J J DHINT
样例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
参考代码
#include <list>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm> struct Card; struct Pig{
Pig(int);
int ID;
int HP;
bool LN;
bool JMP,APL;
bool MP,AP,ZP;
Pig* prev;
Pig* next;
void Jump();
void Clear();
void Round();
void Print();
void Arrows();
void SetAPL();
void Die(Pig*);
void Invasion();
void GetCard(int);
void GetHurt(Pig*);
bool Kill();
bool TryDuel();
bool UseKill();
bool UseMiss();
bool UsePeach();
bool JFor(bool);
bool Duel(Pig*);
bool UseCard(char);
bool FindJBecauseOf(Pig*);
std::list<Card*> cards;
}; struct Card{
Card();
char type;
bool Act(Pig*);
}; int n;
int m;
int APs;
bool END;
char last;
char buf[];
std::vector<Pig*> v; void Initialize(); int main(){
Initialize();
Pig* root=v[];
while(!END){
root->Round();
root=root->next;
}
if(APs==)
puts("MP");
else
puts("FP");
for(std::vector<Pig*>::iterator i=v.begin();i!=v.end();++i)
(*i)->Print();
return ;
} bool Pig::Kill(){
if(this->AP){
if(this->next==v[]||(this->next->ZP&&this->next->JMP)){
this->JMP=true;
if(!this->next->UseMiss())
this->next->GetHurt(this);
return true;
}
}
else if(this->MP){
if(this->next->JMP){
if(this->next->AP){
if(!this->next->UseMiss())
this->next->GetHurt(this);
return true;
}
}
else{
if(this->next->APL){
if(!this->next->UseMiss())
this->next->GetHurt(this);
return true;
}
}
}
else if(this->ZP){
if(this->next->AP&&this->next->JMP){
if(!this->next->UseMiss())
this->next->GetHurt(this);
return true;
}
}
return false;
} bool Pig::TryDuel(){
if(this->AP){
this->JMP=true;
if(!v[]->FindJBecauseOf(this)){
if(v[]->Duel(this))
v[]->GetHurt(this);
else
this->GetHurt(v[]);
}
return true;
}
else if(this->MP){
Pig* root=this->next;
while(root!=this){
if((root->AP&&root->JMP)||(root->APL&&!root->JMP)){
if(!root->FindJBecauseOf(this)){
if(root->Duel(this))
root->GetHurt(this);
else
this->GetHurt(root);
}
return true;
}
root=root->next;
}
}
else if(this->ZP){
Pig* root=this->next;
while(root!=this){
if(root->AP&&root->JMP){
this->JMP=true;
if(!root->FindJBecauseOf(this)){
if(root->Duel(this))
root->GetHurt(this);
else
this->GetHurt(root);
}
return true;
}
root=root->next;
}
}
return ;
} bool Pig::Duel(Pig* source){
if(this->ZP&&source->MP)
return true;
else{
while(true){
if(!this->UseKill())
return true;
if(!source->UseKill())
return false;
}
}
} void Pig::Round(){
this->GetCard();
bool Kused=false;
bool flag=false;
for(std::list<Card*>::iterator i=this->cards.begin();(!this->cards.empty())&&i!=this->cards.end();flag?i:++i){
flag=false;
if(END||this->HP==)
break;
if((*i)->type=='P'&&this->HP<){
this->HP++;
if(!this->cards.empty())
this->cards.erase(i);
i=this->cards.begin();
flag=true;
}
else if((*i)->type=='N'){
this->Invasion();
if(!this->cards.empty())
this->cards.erase(i);
i=this->cards.begin();
flag=true;
}
else if((*i)->type=='W'){
this->Arrows();
if(!this->cards.empty())
this->cards.erase(i);
i=this->cards.begin();
flag=true;
}
else if((*i)->type=='K'&&(!Kused||this->LN)){
if(this->Kill()){
if(!this->cards.empty())
this->cards.erase(i);
i=this->cards.begin();
flag=true;
Kused=true;
}
}
else if((*i)->type=='F'){
if(this->TryDuel()){
if(!this->cards.empty())
this->cards.erase(i);
i=this->cards.begin();
flag=true;
}
}
else if((*i)->type=='Z'){
if(!this->cards.empty())
this->cards.erase(i);
i=this->cards.begin();
flag=true;
if(this->LN==false){
this->LN=true;
}
}
}
} bool Pig::JFor(bool AP){
Pig* root=this;
do{
if(root->AP==AP){
if(root->UseCard('J')){
root->JMP=true;
return !root->JFor(!AP);
}
}
root=root->next;
}while(root!=this);
return false;
} bool Pig::FindJBecauseOf(Pig* source){
if((!this->JMP)&&(!this->MP))
return false;
else{
return source->JFor(this->AP);
}
} void Pig::GetHurt(Pig* source){
this->HP--;
if(this->HP<=){
if(this->UsePeach())
this->HP++;
else
this->Die(source);
}
} void Pig::Clear(){
this->LN=false;
this->cards.clear();
} void Pig::Die(Pig* source){
this->prev->next=this->next;
this->next->prev=this->prev;
if(this->MP)
END=true;
else if(this->AP){
APs--;
if(APs<=){
END=true;
return;
}
source->GetCard();
}
else if(this->ZP&&source->MP){
source->Clear();
}
} bool Pig::UseKill(){
return this->UseCard('K');
} bool Pig::UseMiss(){
return this->UseCard('D');
} bool Pig::UsePeach(){
return this->UseCard('P');
} void Pig::SetAPL(){
if(!this->JMP)
this->APL=true;
} bool Pig::UseCard(char ch){
for(std::list<Card*>::iterator i=this->cards.begin();i!=this->cards.end();++i){
if((*i)->type==ch){
this->cards.erase(i);
return true;
}
}
return false;
} void Initialize(){
scanf("%d%d",&n,&m);
m+=*n;
for(int i=;i<n;i++)
v.push_back(new Pig(i));
v[n-]->next=v[];
v[]->prev=v[n-];
for(int i=;i<n;i++){
v[i-]->next=v[i];
v[i]->prev=v[i-];
}
if(APs==)
END=true;
} Pig::Pig(int ID){
this->ID=ID;
this->LN=false;
this->JMP=this->APL=false;
this->AP=this->ZP=this->MP=false;
this->HP=;
scanf("%s",buf);
if(*buf=='M')
this->MP=true;
else if(*buf=='Z')
this->ZP=true;
else
this->AP=true;
this->GetCard();
if(this->AP)
APs++;
} Card::Card(){
if(m>){
scanf("%s",buf);
this->type=*buf;
last=this->type;
m--;
}
else
this->type=last;
} void Pig::Arrows(){
Pig* root=this->next;
while(root!=this){
if(root->FindJBecauseOf(this)){
root=root->next;// QAQ
continue;
}
if(!root->UseMiss()){
if(root->MP)
this->SetAPL();
root->GetHurt(this);
}
if(END)
return;
root=root->next;
}
} void Pig::Invasion(){
Pig* root=this->next;
while(root!=this){
if(root->FindJBecauseOf(this)){
root=root->next;// QAQ
continue;
}
if(!root->UseKill()){
if(root->MP)
this->SetAPL();
root->GetHurt(this);
}
if(END)
return;
root=root->next;
}
} void Pig::GetCard(int cnt){
while(cnt--)
this->cards.push_back(new Card());
} void Pig::Print(){
if(this->HP<=)
puts("DEAD");
else{
while(!this->cards.empty()){
putchar(this->cards.front()->type);
this->cards.pop_front();
if(!this->cards.empty())
putchar(' ');
}
putchar('\n');
}
}
Backup
(补图了补图了)