【题解】Luogu-P2482 SDOI2010 猪国杀

发布时间 2023-09-02 15:58:02作者: SoyTony

写了 \(358\) 行,\(11.94 \mathrm{KB}\),有这么几个地方写挂了:

  • 反猪决斗一定选主猪。

  • 游戏结束判定是主猪死亡或全部反猪死亡。

  • 决斗可能被反杀,之后不能再出牌。

点击查看代码
#include<bits/stdc++.h>
using namespace std;

int n,m;
char Ch[3];

queue<char> Deck;

int Count_Identities[4];
int Count_Players;
int Previous_Player[11],Next_Player[11];
inline void Erase_Player(int Player_Number){
    Next_Player[Previous_Player[Player_Number]]=Next_Player[Player_Number];
    Previous_Player[Next_Player[Player_Number]]=Previous_Player[Player_Number];
    --Count_Players;
}

struct PLAYER{
    int Identity,Current_Identity;
    int HP;
    bool Dead;
    int Card_Queue_Head,Card_Queue_Tail,Count_Cards;
    int Previous_Card[2005],Next_Card[2005];
    char Card_Type[2005];
    bool K_Played,Z_Played;
    inline void Input();
    inline void Get_Card();
    inline void Erase_Card(int Card_Number);
    inline void Check_Dead(int Player_Number,int Source_Player_Number);
    inline void Output_Cards();
    inline bool P_Play(int Card_Number);
    inline bool K(int Player_Number,int Card_Number);
    inline bool K_Play();
    inline bool D_Play();
    inline bool F_Check(int Player_Number,int Card_Number);
    inline void F_Play(int Player_Number,int Source_Player_Number);
    inline bool N(int Player_Number,int Card_Number);
    inline bool W(int Player_Number,int Card_Number);
    inline int J_Check(int Player_Number,int Source_Player_Number,bool Type);
    inline bool J_Play(int Player_Number);
    inline bool Z(int Player_Number);
    inline void Play(int Player_Number);
}Player[11];

inline void PLAYER::Input(){
    scanf("%s",Ch);
    if(Ch[0]=='M') Identity=1;
    else if(Ch[0]=='Z') Identity=2;
    else Identity=3;
    ++Count_Identities[Identity];
    Current_Identity=0;
    HP=4;
    Dead=false;
    Card_Queue_Head=1,Card_Queue_Tail=4,Count_Cards=4;
    for(int i=1;i<=4;++i){
        scanf("%s",Ch);
        Previous_Card[i]=i-1,Next_Card[i]=i+1;
        Card_Type[i]=Ch[0];
    }
    Previous_Card[1]=-1,Next_Card[4]=-1;
    K_Played=false,Z_Played=false;
}
inline void PLAYER::Get_Card(){
    ++Count_Cards;
    Card_Type[Count_Cards]=Deck.front();
    Previous_Card[Count_Cards]=Card_Queue_Tail,Next_Card[Count_Cards]=-1;
    if(Card_Queue_Tail!=-1) Next_Card[Card_Queue_Tail]=Count_Cards;
    else Card_Queue_Head=Count_Cards;
    Card_Queue_Tail=Count_Cards;
    if((int)Deck.size()>1) Deck.pop(); 
}
inline void PLAYER::Erase_Card(int Card_Number){
    if(Card_Number==Card_Queue_Head) Card_Queue_Head=Next_Card[Card_Number];
    else Next_Card[Previous_Card[Card_Number]]=Next_Card[Card_Number];
    if(Card_Number==Card_Queue_Tail) Card_Queue_Tail=Previous_Card[Card_Number];
    else Previous_Card[Next_Card[Card_Number]]=Previous_Card[Card_Number];
}
inline void PLAYER::Check_Dead(int Player_Number,int Source_Player_Number){
    --HP;
    if(HP) return;
    for(int i=Card_Queue_Head;i!=-1;i=Next_Card[i]){
        if(Card_Type[i]!='P') continue;
        P_Play(i);
        return;        
    }
    Dead=true;
    --Count_Identities[Identity];
    Erase_Player(Player_Number);
    if(!Count_Identities[3]){
        printf("MP\n");
        for(int i=1;i<=n;++i){
            if(Player[i].Dead) printf("DEAD\n");
            else Player[i].Output_Cards();
        }
        exit(0);
    }
    else if(!Count_Identities[1]){
        printf("FP\n");
        for(int i=1;i<=n;++i){
            if(Player[i].Dead) printf("DEAD\n");
            else Player[i].Output_Cards();
        }
        exit(0);
    }
    if(Identity==3){
        Player[Source_Player_Number].Get_Card(),Player[Source_Player_Number].Get_Card(),Player[Source_Player_Number].Get_Card();
    }
    else if(Player[Source_Player_Number].Identity==1&&Identity==2){
        Player[Source_Player_Number].Card_Queue_Head=Player[Source_Player_Number].Card_Queue_Tail=-1;
        Player[Source_Player_Number].Z_Played=false;
    }
}
inline void PLAYER::Output_Cards(){
    for(int i=Card_Queue_Head;i!=-1;i=Next_Card[i]) printf("%c ",Card_Type[i]);
    printf("\n");
}
inline bool PLAYER::P_Play(int Card_Number){
    if(HP<4){
        ++HP;
        Erase_Card(Card_Number);
        return true;
    }
    else return false;
}
inline bool PLAYER::K(int Player_Number,int Card_Number){
    if(K_Played&&!Z_Played) return false;
    if(Identity==1&&(Player[Next_Player[Player_Number]].Current_Identity==2||Player[Next_Player[Player_Number]].Current_Identity==3)){
        Erase_Card(Card_Number);
        bool D_Played=Player[Next_Player[Player_Number]].D_Play();
        if(!D_Played) Player[Next_Player[Player_Number]].Check_Dead(Next_Player[Player_Number],Player_Number);
    }
    else if(Identity==2&&Player[Next_Player[Player_Number]].Current_Identity==2){
        Erase_Card(Card_Number);
        bool D_Played=Player[Next_Player[Player_Number]].D_Play();
        if(!D_Played) Player[Next_Player[Player_Number]].Check_Dead(Next_Player[Player_Number],Player_Number);
        Current_Identity=1;
    }
    else if(Identity==3&&(Player[Next_Player[Player_Number]].Identity==1||Player[Next_Player[Player_Number]].Current_Identity==1)){
        Erase_Card(Card_Number);
        bool D_Played=Player[Next_Player[Player_Number]].D_Play();
        if(!D_Played) Player[Next_Player[Player_Number]].Check_Dead(Next_Player[Player_Number],Player_Number);
        Current_Identity=2;
    }
    else return false;
    K_Played=true;
    return true;
}
inline bool PLAYER::K_Play(){
    for(int i=Card_Queue_Head;i!=-1;i=Next_Card[i]){
        if(Card_Type[i]!='K') continue;
        Erase_Card(i);
        return true;
    }
    return false;
}
inline bool PLAYER::D_Play(){
    for(int i=Card_Queue_Head;i!=-1;i=Next_Card[i]){
        if(Card_Type[i]!='D') continue;
        Erase_Card(i);
        return true;
    }
    return false;
}
inline bool PLAYER::F_Check(int Player_Number,int Card_Number){
    if(Identity!=3){
        for(int i=Next_Player[Player_Number];i!=Player_Number;i=Next_Player[i]){
            if(
                (Identity==1&&(Player[i].Current_Identity==2||Player[i].Current_Identity==3))||
                (Identity==2&&Player[i].Current_Identity==2)){
                Current_Identity=1;
                Erase_Card(Card_Number);
                F_Play(i,Player_Number);
                return true;
            }
        }
    }
    else{
        Current_Identity=2;
        Erase_Card(Card_Number);
        F_Play(1,Player_Number);
        return true;
    }
    return false;
}
inline void PLAYER::F_Play(int Player_Number,int Source_Player_Number){
    bool Type=false;
    int Temporary_Source_Player_Number=Source_Player_Number;
    while(1){
        int J_Played=Player[Player_Number].J_Check(Player_Number,Source_Player_Number,Type);
        if(!J_Played) break;
        Source_Player_Number=J_Played,Type^=1;
    }
    if(Type) return;
    Source_Player_Number=Temporary_Source_Player_Number;
    bool Turn=false;
    while(1){
        if(!Turn){
            bool FK_Played;
            if(Identity==1&&Player[Player_Number].Identity==2) FK_Played=false;
            else FK_Played=Player[Player_Number].K_Play();
            if(!FK_Played){
                Player[Player_Number].Check_Dead(Player_Number,Source_Player_Number);
                return;
            }
        }
        else{
            bool FK_Played;
            if(Player[Player_Number].Identity==1&&Identity==2) FK_Played=false;
            else FK_Played=K_Play();
            if(!FK_Played){
                Check_Dead(Source_Player_Number,Player_Number);
                return;
            }
        }
        Turn^=1;
    }
}
inline bool PLAYER::N(int Player_Number,int Card_Number){
    Erase_Card(Card_Number);
    int Source_Player_Number;
    for(int i=Next_Player[Player_Number];i!=Player_Number;i=Next_Player[i]){
        bool Type=false;
        Source_Player_Number=Player_Number;
        while(1){
            int J_Played=Player[i].J_Check(i,Source_Player_Number,Type);
            if(!J_Played) break;
            Source_Player_Number=J_Played,Type^=1;
        }
        if(Type) continue;
        Source_Player_Number=Player_Number;
        bool NK_Played=Player[i].K_Play();
        if(!NK_Played){
            if(Player[i].Identity==1&&!Current_Identity) Current_Identity=3;
            Player[i].Check_Dead(i,Source_Player_Number);
        }
    }
    return true;
}
inline bool PLAYER::W(int Player_Number,int Card_Number){
    Erase_Card(Card_Number);
    int Source_Player_Number;
    for(int i=Next_Player[Player_Number];i!=Player_Number;i=Next_Player[i]){
        bool Type=false;
        Source_Player_Number=Player_Number;
        while(1){
            int J_Played=Player[i].J_Check(i,Source_Player_Number,Type);
            if(!J_Played) break;
            Source_Player_Number=J_Played,Type^=1;
        }
        if(Type) continue;
        Source_Player_Number=Player_Number;
        bool WD_Played=Player[i].D_Play();
        if(!WD_Played){
            if(Player[i].Identity==1&&!Current_Identity) Current_Identity=3;
            Player[i].Check_Dead(i,Source_Player_Number);
        }
    }
    return true;
}
inline int PLAYER::J_Check(int Player_Number,int Source_Player_Number,bool Type){
    if(Identity!=1&&Current_Identity!=1&&Current_Identity!=2) return 0;
    bool Source_Player_Visited=false;
    for(int i=Source_Player_Number;;i=Next_Player[i]){
        if(i==Source_Player_Number){
            if(Source_Player_Visited) return 0;
            else Source_Player_Visited=true;
        }
        if(!Type){
            if(
                (Identity==1&&(Player[i].Identity==1||Player[i].Identity==2))||
                (Current_Identity==1&&(Player[i].Identity==1||Player[i].Identity==2))){
                bool J_Played=Player[i].J_Play(i);
                if(J_Played){
                    Player[i].Current_Identity=1;
                    return i;
                } 
            }
            else if(Current_Identity==2&&Player[i].Identity==3){
                bool J_Played=Player[i].J_Play(i);
                if(J_Played){
                    Player[i].Current_Identity=2;
                    return i;
                } 
            }
        }
        else{
            if(
                (Identity==1&&Player[i].Identity==3)||
                (Current_Identity==1&&Player[i].Identity==3)){
                bool J_Played=Player[i].J_Play(i);
                if(J_Played){
                    Player[i].Current_Identity=2;
                    return i;
                } 
            }
            else if(
                (Current_Identity==2&&(Player[i].Identity==1||Player[i].Identity==2))||
                (Current_Identity==3&&Player[i].Identity==1)){
                bool J_Played=Player[i].J_Play(i);
                if(J_Played){
                    Player[i].Current_Identity=1;
                    return i;
                } 
            }
        }
    }
}
inline bool PLAYER::J_Play(int Player_Number){
    for(int i=Card_Queue_Head;i!=-1;i=Next_Card[i]){
        if(Card_Type[i]!='J') continue;
        Erase_Card(i);
        return true;
    }
    return false;
}
inline bool PLAYER::Z(int Card_Number){
    Z_Played=true;
    Erase_Card(Card_Number);
    return true;
}

inline void PLAYER::Play(int Player_Number){
    Get_Card(),Get_Card();
    K_Played=false;
    while(1){
        bool Played=false;
        for(int i=Card_Queue_Head;i!=-1;i=Next_Card[i]){
            if(Card_Type[i]=='P') Played=P_Play(i);
            else if(Card_Type[i]=='K') Played=K(Player_Number,i);
            else if(Card_Type[i]=='F') Played=F_Check(Player_Number,i);
            else if(Card_Type[i]=='N') Played=N(Player_Number,i);
            else if(Card_Type[i]=='W') Played=W(Player_Number,i);
            else if(Card_Type[i]=='Z') Played=Z(i);
            else continue;
            if(Played) break;
        }
        if(Dead) break;
        if(!Played) break;
    }
}

int main(){
    scanf("%d%d",&n,&m);
    Count_Players=n;
    for(int i=1;i<=n;++i) Player[i].Input();
    for(int i=1;i<=m;++i){
        scanf("%s",Ch);
        Deck.push(Ch[0]);
    }
    for(int i=1;i<=n;++i) Previous_Player[i]=i-1,Next_Player[i]=i+1;
    Previous_Player[1]=n,Next_Player[n]=1;
    int Current_Player=1;
    while(1){
        Player[Current_Player].Play(Current_Player);
        Current_Player=Next_Player[Current_Player];
    }
    return 0;
}