LOJ 2885: 洛谷 P2482: 「SDOI2010」猪国杀

终于A了这题
发一篇题解供人参考
同时谢谢这位dalao所述的注意事项给了我很多提醒
思路都在注释里了

#include <iostream>
#include <cstdio>

using namespace std;

const int N = 15, M = 2010;

struct pig
{
    int hp, size; //生命,手牌数
    char id; //身份
    char cards[M]; //手牌
    bool zhuge; //有没有武器
}a[N]; 

int Pre[N], Next[N]; //每只猪的前一个和后一个
int n, m;
int fp_sum; //反猪数量
char mp_look[N], card_stack[M], str[N]; //在主猪看来每只猪的身份,也是每只猪已经跳的身份, 卡牌堆, 输入用的临时字符串
bool end_game; //游戏是否结束

/*
void Debug() //调试用
{
    puts("");
    for (int i = 1; i <= n; i++)
    {
        printf("a[%d].hp=%d\n", i, a[i].hp);
        printf("a[%d].size=%d\n", i, a[i].size);
        printf("a[%d].Pre=%d\n", i, Pre[i]);
        printf("a[%d].Next=%d\n", i, Next[i]);
        printf("a[%d].id=%c\n", i, a[i].id);
        printf("a[%d].zhuge=%d\n", i, a[i].zhuge);
        printf("a[%d].cards[]: ", i);for (int j = 1; j <= a[i].size; j++) printf("%c ", a[i].cards[j]);puts("");
    }
    puts("");
}
*/

void get_card(int x)
{
    //没牌时重复抓最后一张
    if (m == 0) m++;
    a[x].cards[++a[x].size] = card_stack[m--];
}

void KO(int x, int y)
{
    //是否有桃,有就用
    for (int i = 1; i <= a[y].size; i++)
        if (a[y].cards[i] == 'P') 
        {
            a[y].cards[i] = '#';
            a[y].hp++;
            return ;
        }    

    //判断是否结束
    if (a[y].id == 'F') fp_sum--;
    if (y == 1 || fp_sum == 0)
    {
        end_game = true;
        return ;
    } 

    //改变攻击距离
    Pre[Next[y]] = Pre[y];
    Next[Pre[y]] = Next[y];

    //杀反贼,摸三张
    if (a[y].id == 'F')
    {
        get_card(x);
        get_card(x);
        get_card(x);
    }

    //主杀忠,弃全部牌
    if (x == 1 && a[y].id == 'Z')
    {
        a[x].size = 0;
        a[x].zhuge = false;
    }
}

void Kill(int x, int y)
{
    //是否有闪
    for (int i = 1; i <= a[y].size; i++)
        if (a[y].cards[i] == 'D') 
        {
            a[y].cards[i] = '#';
            return ;
        }

    //没闪,减血
    a[y].hp--;
    if (a[y].hp <= 0) KO(x, y);
}

bool wxkj(int x, int y, bool z)
{
    //z表示是否是递归的
    int i = x;
    while (1)
    {
        if (z)
        {
            //无条件帮队友
            if (mp_look[y] == a[i].id || (mp_look[y] == 'M' && a[i].id == 'Z') || (mp_look[y] == 'Z' && a[i].id == 'M'))
                for (int j = 1; j <= a[i].size; j++)
                    if (a[i].cards[j] == 'J')
                    {
                        a[i].cards[j] = '#';
                        mp_look[i] = a[i].id; //跳身份
                        return !wxkj(i, x, 0);
                    }
        }
        else
        {
            //无条件无懈敌对
            if ((mp_look[x] == 'F' && (a[i].id == 'M' || a[i].id == 'Z')) || (a[i].id == 'F' && (mp_look[x] == 'M' || mp_look[x] == 'Z')))
                for (int j = 1; j <= a[i].size; j++)
                    if (a[i].cards[j] == 'J')
                    {
                        a[i].cards[j] = '#';
                        mp_look[i] = a[i].id; //跳身份
                        return !wxkj(i, x, 0);
                    }
        }

        i = Next[i]; //下一个
        if (i == x) break; //如果转一圈了,break
    }
    return false;
}

void aoe(int x, char ch)
{
    //群伤,ch表示每个角色要依次出杀还是依次出闪
    for (int i = Next[x]; i != x; i = Next[i])
    {
        if (!wxkj(x, i, true)) //不能被无懈
        {
            int j;
            for (j = 1; j <= a[i].size; j++) 
                if (a[i].cards[j] == ch) //查看有没有,有就出
                {
                    a[i].cards[j] = '#';
                    break;
                }
            if (j > a[i].size) //没有,减血
            {
                a[i].hp--;
                if (i == 1 && mp_look[x] == '#') mp_look[x] = 'L';
                if (a[i].hp == 0) KO(x, i);
                if (end_game) return ; 
            }
        }
    }
}

void duel(int x, int y)
{
    //决斗
    int i = 1, j = 1;
    if (wxkj(x, y, true)) return ; //能被无懈,return

    if (x == 1 && a[y].id == 'Z') //忠猪不对主猪决斗
    {
        a[y].hp--;
        if (a[y].hp == 0) KO(x, y);
        return ;
    }

    while (1) //依次出杀,有就一定出
    {
        while (a[y].cards[i] != 'K' && i <= a[y].size) i++;
        if (i > a[y].size)
        {
            a[y].hp--;
            if (a[y].hp == 0) KO(x, y);
            return ;
        }
        else a[y].cards[i] = '#';

        while (a[x].cards[j] != 'K' && j <= a[x].size) j++;
        if (j > a[x].size)
        {
            a[x].hp--;
            if (a[x].hp == 0) KO(y, x);
            return ;
        }
        else a[x].cards[j] = '#';
    }
}

void init()
{
    scanf("%d%d", &n, &m);
    
    //初始化每头猪的前一只和后一只
    Pre[1] = n, Next[1] = 2;
    Pre[n] = n - 1, Next[n] = 1;
    for (int i = 2; i < n; i++)
    {
        Pre[i] = i - 1;
        Next[i] = i + 1;
    }

    //初始化主猪对每只猪的看法
    mp_look[1] = 'M';
    for (int i = 2; i <= n; i++) mp_look[i] = '#';

    //输入每只猪的信息
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j < M; j++) a[i].cards[j] = '#';
        scanf("%s", str);
        a[i].id = str[0];
        for (int j = 1; j <= 4; j++) 
        {
            scanf("%s", str);
            a[i].cards[j] = str[0];
        }
        a[i].hp = a[i].size = 4;
        if (a[i].id == 'F') fp_sum++;
        a[i].zhuge = false;
    }

    //输入排队,逆序存
    for (int i = 1; i <= m; i++) 
    {
        scanf("%s", str);
        card_stack[m - i + 1] = str[0];
    }
}

void work()
{
    //有没有反猪,没有直接return
    end_game = fp_sum ? false : true;
    if (end_game) return ;

    for (int i = 1; i; i = Next[i]) //依次摸牌
    {
        get_card(i);
        get_card(i);

        bool flag = false; //有没有用过杀
        
        for (int j = 1; j <= a[i].size; j++)
        {
            if (a[i].cards[j] != '#')
            {
                if (a[i].hp <= 0) break; //死了,break

                if (a[i].cards[j] == 'P') //是否吃桃
                {
                    if (a[i].hp < 4) 
                    {
                        a[i].cards[j] = '#';
                        a[i].hp++;
                    }
                    continue;
                }
                if (a[i].cards[j] == 'K') //杀
                {
                    if (flag && !a[i].zhuge) continue; //用过杀了且没有猪哥连弩
                    if (a[i].id == 'M' && mp_look[Next[i]] != 'F' && mp_look[Next[i]] != 'L') continue; //主猪不杀反猪和类反猪以外的猪
                    if (a[i].id == 'Z' && mp_look[Next[i]] != 'F') continue; //忠猪不杀反猪以外的猪
                    if (a[i].id == 'F' && mp_look[Next[i]] != 'M' && mp_look[Next[i]] != 'Z') continue; //反猪不杀主猪和忠猪以外的猪
                    a[i].cards[j] = '#'; //否则就杀
                    Kill(i, Next[i]);
                    mp_look[i] = a[i].id; //跳身份
                    flag = true; //用过了
                    if (end_game) return ;
                    continue;
                }
                if (a[i].cards[j] == 'F')
                {
                    if (a[i].id == 'F')
                    {
                        a[i].cards[j] = '#'; //是反猪就直接对主猪用
                        duel(i, 1);
                        mp_look[i] = a[i].id;
                        if (end_game) return ;
                        j = 0; //可能掉血,须从新扫一遍,看有没有桃
                        continue;
                    }
                    for (int k = Next[i]; k != i; k = Next[k]) //找对谁使用
                    {
                        if ((a[i].id == 'M' && (mp_look[k] == 'F' || mp_look[k] == 'L')) || (a[i].id == 'Z' && mp_look[k] == 'F'))
                        {
                            a[i].cards[j] = '#';
                            duel(i, k);
                            mp_look[i] = a[i].id; //跳身份
                            if (end_game) return ;
                            j = 0; //可能掉血,须从新扫一遍,看有没有桃
                            break;
                        }
                    }
                    continue;
                }
                if (a[i].cards[j] == 'N' || a[i].cards[j] == 'W') //群体伤害,直接用
                {
                    if (a[i].cards[j] == 'N') aoe(i, 'K'); //每只猪出杀
                    else aoe(i, 'D'); //每只猪出闪
                    a[i].cards[j] = '#';
                    
                    if (end_game) return ;
                    j = 0; ////可能掉血,须从新扫一遍,看有没有桃
                    continue;
                }
                if (a[i].cards[j] == 'Z') //猪哥连弩,直接装
                {
                    a[i].cards[j] = '#';
                    a[i].zhuge = true;
                    j = 0; //从新扫一边看又没有杀
                    continue;
                }
            }
        }
    }
}

void print()
{
    //看是主猪赢还是反猪赢
    if (fp_sum <= 0) puts("MP");
    else puts("FP");

    //输出每只猪的状态
    for (int i = 1; i <= n; i++)
    {
        if (a[i].hp <= 0) 
        {
            puts("DEAD");
            continue;
        }

        for (int j = 1; j <= a[i].size; j++) if (a[i].cards[j] != '#') printf("%c ", a[i].cards[j]);
        puts("");
    }
}

int main()
{
    init();
    work();
    print();    

    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Saudi/p/11437694.html