题解 P2482 【[SDOI2010]猪国杀】

· · 题解

之前这个代码有些注释有bug,现已修复重新提交【给我过吧QAQ我辣么可怜】

首先我的这段代码参考过了hzwerdalao的做法但是大概架构是我打的只是有些小bug和他的代码对拍而已QAQ
四位dalao都把一些注意事项和小坑都给列出来了,我就贴个有注释的代码吧……【打了我四个中午还鸽了一会QAQ】

/*
牌库为空之后再抽牌,会重复抽最后一张被抽走牌
主公死或反贼全死都中断游戏,直接进入输出阶段
所有人一开始都知道主公的身份
每个人都会无条件帮队友无懈掉决斗【万箭】【南蛮】
每个人都会无条件【无懈】掉对手的【无懈】
每个人都不会【无懈】掉队友的【无懈】
反贼只会【决斗】主公
忠臣被主公【决斗】并不能算跳忠
主公杀了忠臣要清空所有牌以及【诸葛连弩】
杀死反贼摸三张牌
*/
/*
桃 P
杀 K
闪 D
决斗 F
南蛮入侵 N
万箭齐发 W
无懈可击 J
诸葛连弩 Z 
*/
#include<bits/stdc++.h>
using namespace std;

struct node{
    int cs,hp,next,last;
    //cs=cardsize=手牌数
    //hp 生命值 
    char id,card[2010];
    //id=identity=身份 
    bool zgln;
    //是否装备了【诸葛连弩】 
}a[20];
char kn[11],kpd[2010],sss[10];
//kn表示在主公眼里这只猪的身份
//kpd 卡牌堆 
int n,m,fz;
//fz 反贼数量 
bool ed;

void mp(int x)
//【摸牌】
{
    if(!m) m++;
    a[x].card[++a[x].cs]=kpd[m];
    m--;
}

void js(int x1,int x2)
//【击杀】 
{
    for(int i=1;i<=a[x2].cs;i++)
        if(a[x2].card[i]=='P')
        //判断是否有【桃】 
        {
            a[x2].card[i]='U';
            a[x2].hp++;
            return ;
        }
    a[a[x2].next].last=a[x2].last;
    a[a[x2].last].next=a[x2].next;
    //死亡后改变攻击距离 
    if(x2==1){ed=true;return ;}
    if(a[x2].id=='F') fz--;
    if(!fz){ed=true;return ;}
    //没有反贼游戏结束 
    if(a[x2].id=='F') mp(x1),mp(x1),mp(x1);
    //击杀反贼摸三张牌 
    if(a[x2].id=='Z' && a[x1].id=='M') a[x1].cs=0,a[x1].zgln=false;
    //如果主公把忠臣杀了那就要弃牌 
}

void Kil(int x1,int x2)
//【杀】 
{
    for(int i=1;i<=a[x2].cs;i++)
        if(a[x2].card[i]=='D')
        {
            a[x2].card[i]='U';
            return ;
        }
    a[x2].hp--;
    if(!a[x2].hp) js(x1,x2);
    //每次造成伤害都要判断被攻击者是否空血
    //然后进入【击杀】环节 
}

bool wxkj(int x1,int x2,int x3)
//【无懈可击】 
{
    int i=x1,pd=x3?x2:x1;
    while(1)
    {
        if(x3==1)
        {
            if(kn[x2]==a[i].id || (kn[x2]=='M' && a[i].id=='Z') || (kn[x2]=='Z' && a[i].id=='M'))
            //假如是敌对的那就【无懈可击】掉
                for(int j=1;j<=a[i].cs;j++)
                    if(a[i].card[j]=='J')
                    {
                        a[i].card[j]='U';
                        kn[i]=a[i].id;
                        return !wxkj(i,x1,0);
                    }
        }
        else
        {
            if(((a[i].id=='M' || a[i].id=='Z') && kn[x1]=='F') || (a[i].id=='F' && (kn[x1]=='M' || kn[x1]=='Z')))
                for(int j=1;j<=a[i].cs;j++)
                    if(a[i].card[j]=='J')
                    {
                        a[i].card[j]='U';
                        kn[i]=a[i].id;
                        return !wxkj(i,x1,0);
                    }
        }
        i=a[i].next;
        if(i==x1) break;
        //没有人用【无懈可击】抵挡此【无懈可击】那么这张牌就生效 
    }
    return false;
}

void nmrq(int x1)
//【南蛮入侵】
{
    for(int x2=a[x1].next;x2!=x1;x2=a[x2].next)
    //进行一个循环来出牌 
        if(!wxkj(x1,x2,1))
        //判断是否被【无懈可击】掉 
        {
            int i;
            for(i=1;i<=a[x2].cs;i++)
                if(a[x2].card[i]=='K')
                {
                    a[x2].card[i]='U';
                    break;
                }
            if(i>a[x2].cs)
            {
                a[x2].hp--;
                if(x2==1 && kn[x1]=='U') kn[x1]='L';
                if(!a[x2].hp) js(x1,x2);
                if(ed) return ;
            }
        }
}

void wjqf(int x1)
//【万箭齐发】 
{
    for(int x2=a[x1].next;x2!=x1;x2=a[x2].next)
        if(!wxkj(x1,x2,1))
        //判断是否被【无懈可击】掉 
        {
            int i;
            for(i=1;i<=a[x2].cs;i++)
                if(a[x2].card[i]=='D')
                {
                    a[x2].card[i]='U';
                    break;
                }
            if(i>a[x2].cs)
            {
                a[x2].hp--;
                if(x2==1 && kn[x1]=='U') kn[x1]='L';
                if(!a[x2].hp) js(x1,x2);
                if(ed) return ;
            }
        }
}

void jd(int x1,int x2)
//【决斗】 
{
    int i,j,k;
    if(wxkj(x1,x2,1)) return ;
    //判断是否被【无懈可击】掉 
    if(x1==1 && a[x2].id=='Z')
    {
        a[x2].hp--;
        if(!a[x2].hp) js(x1,x2);
        return ;
    }
    j=k=1;
    while(1)
    {
        while(a[x2].card[j]!='K' && j<=a[x2].cs) j++;
        if(j>a[x2].cs)
        {
            a[x2].hp--;
            if(!a[x2].hp) js(x1,x2);
            return ;
        }
        else a[x2].card[j]='U';
        while(a[x1].card[k]!='K' && k<=a[x1].cs) k++;
        if(k>a[x1].cs)
        {
            a[x1].hp--;
            if(!a[x1].hp) js(x2,x1);
            return ;
        }
        else a[x1].card[k]='U';
    }
}

void hh()
//进入回合 
{
    char nc;
    ed=true;
    if(fz) ed=false;
    if(ed) return ;
    for(int i=1;i;i=a[i].next)
    {
        mp(i),mp(i);
        bool kill=true;
        for(int j=1;j<=a[i].cs;j++)
            if(a[i].card[j]!='U')
            //=='U'就是被使用过,弃置了 
            {
                if(!a[i].hp) break;
                nc=a[i].card[j];
                //nc=now-card=现在的手牌 
                if(nc=='P')
                //使用【桃】
                {
                    if(a[i].hp!=4) a[i].hp++,a[i].card[j]='U';
                    continue;
                }
                if(nc=='K')
                //使用【杀】 
                {
                    if(!kill && !a[i].zgln) continue;
                    if(a[i].id=='M' && kn[a[i].next]!='L' && kn[a[i].next]!='F') continue;
                    if(a[i].id=='Z' && kn[a[i].next]!='F') continue;
                    if(a[i].id=='F' && kn[a[i].next]!='Z' && kn[a[i].next]!='M') continue;
                    a[i].card[j]='U';
                    Kil(i,a[i].next);
                    kn[i]=a[i].id,kill=false;
                    if(ed) return ;
                    continue;
                }
                if(nc=='F')
                //使用【决斗】
                {
                    if(a[i].id=='F')
                    {
                        a[i].card[j]='U',jd(i,1);
                        kn[i]=a[i].id;
                        if(ed) return ;
                        j=0;
                        continue;
                    }
                    for(int k=a[i].next;k!=i;k=a[k].next)
                        if((a[i].id=='M' && (kn[k]=='L' || kn[k]=='F')) || (a[i].id=='Z' && kn[k]=='F'))
                        {
                            a[i].card[j]='U',jd(i,k);
                            kn[i]=a[i].id;
                            if(ed) return ;
                            j=0;
                            break;
                        }
                    continue;
                }
                if(nc=='N')
                //使用【南蛮入侵】
                {
                    a[i].card[j]='U';
                    nmrq(i);
                    if(ed) return ;
                    j=0;
                    continue;
                }
                if(nc=='W')
                //使用【万箭齐发】 
                {
                    a[i].card[j]='U';
                    wjqf(i);
                    if(ed) return ;
                    j=0;
                    continue;
                }
                if(nc=='Z')
                //装备【诸葛连弩】 
                {
                    a[i].zgln=true;
                    a[i].card[j]='U';
                    j=0;
                    continue;
                }
            }
    }
}

int main()
{
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++) a[i].next=i+1,a[i].last=i-1;
    //攻击距离 
    a[n].next=1,a[1].last=n;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<2010;j++) a[i].card[j]='U';
        scanf("%s",sss);a[i].id=sss[0];
        for(int j=1;j<=4;j++) scanf("%s",sss),a[i].card[j]=sss[0];
        a[i].cs=a[i].hp=4;
        //手牌上限和血量上限都是4 
        if(a[i].id=='F') fz++;
        //统计反贼的数量 
        a[i].zgln=false;
    }
    for(int i=2;i<=n;i++) kn[i]='U';
    kn[1]='M';
    for(int i=1;i<=m;i++) scanf("%s",sss),kpd[m-i+1]=sss[0];
    hh();
    //进入回合 
    if(a[1].hp<=0) printf("FP\n");
    else printf("MP\n");
    //看看主公有没有挂 
    for(int i=1;i<=n;i++)
    {
        if(a[i].hp<=0) printf("DEAD\n");
        //空血凉凉 
        else
        //亮牌 
        {
            for(int j=1;j<=a[i].cs;j++)
                if(a[i].card[j]!='U') printf("%c ",a[i].card[j]);
                //若该手牌没有被弃置则输出 
            printf("\n");
        }
    }
    return 0;
}