[BZOJ2548][Ctsc2002]灭鼠行动(大模拟)

题目描述

传送门

题解

又是一道大模拟。。。
需要注意的几个地方:
1、一个时刻x+时间单位x~y操作的顺序是:时刻x老鼠繁殖、时刻x放武器、判断是否发生鼠疫、时间单位x~y老鼠移动。
2、只有某一个点上有且仅有两只老鼠并且满足性别互异、均成年、不在上一次繁殖期间或者昏迷状态下才可以繁殖。
3、某一次繁殖结束之后(等待+繁殖+休息),如果两只老鼠又进行了一次操作(走一步或者转一下方向),并且又同时到了同一个点上,那么它们可以接着繁殖。
4、在昏迷过程中,所有的生理活动都被暂停,包括:年龄增长、繁殖或休息的时间。
5、在繁殖过程中(等待+繁殖+休息)都不能移动。

代码

#include
#include
#include
#include
#include
using namespace std;

int n,m,L,R,P,limit,T,now;
bool plague;
struct RAT
{
    // 当前位置
    int x,y;
    // 朝向 0 上 1 右 2 下 3 左 
    int dir; 
    // 性别 0 雄性 1 雌性 
    int sex;
    // 年龄
    int age;
    // 还需要再等待re时间才能恢复生理活动 
    int re;
    // 第几次遇到两边都有路的情况
    int cnt;
    // 还需要再等待multi时间才能生出小老鼠,若multi=-1则并没有进行繁殖 
    int multi;
    // 还需要再等待move时间才能运动(繁殖之后),若move=-1说明并不是繁殖刚结束,可以接着繁殖 
    int move; 
    // 是否已经死亡 1 死亡 
    bool dead;
}rat[405],bag[405];
struct GUN
{
    // 武器的类型 1 强力炸弹 2 神秘射线 3 定时炸弹 4 生物炸弹 
    int type;
    // 放置的时间
    int t;
    // 放置的位置
    int x,y;
    bool operator < (const GUN &a) const
    {
        return t105];
// 目前的老鼠总数
int tot;
// 下水道中每一个位置的结构 
int loc[55][55];
// 方向转化为二进制数
int trans[4]={1,2,4,8};
// 四种走法
int dx[4]={-1,0,1,0};int dy[4]={0,1,0,-1}; 
// 判断每一个位置是否被当前的强力炸弹攻击到 
bool vis[55][55]; 
// 当前时刻下水道中每一个位置存在的老鼠集合、大小
int s[55][55][405],size[55][55];

void Multi()
{
    memset(size,0,sizeof(size));
    // 统计每一个点有多少只老鼠 
    for (int i=1;i<=tot;++i)
    {
        int x=rat[i].x,y=rat[i].y;
        s[x][y][++size[x][y]]=i;
    }
    for (int i=1;i<=n;++i)
        for (int j=1;j<=m;++j)
            // 如果某一个点只有两只老鼠 
            if (size[i][j]==2)
            {
                int id=s[i][j][1],jd=s[i][j][2];
                // 性别互异 
                if (rat[id].sex==rat[jd].sex) continue;
                // 成年 
                if (rat[id].age<5||rat[jd].age<5) continue;
                // 如果未恢复生理活动
                if (rat[id].re||rat[jd].re) continue; 
                // 如果在生育过程中 
                if (rat[id].multi!=-1||rat[jd].multi!=-1) continue;
                // 如果在休息过程中
                if (rat[id].move!=-1||rat[jd].move!=-1) continue; 
                rat[id].multi=rat[jd].multi=2;
            }
    for (int i=1;i<=tot;++i)
    {
        // 如果 未恢复生理活动 或者 在休息过程中 
        if (rat[i].re||rat[i].move!=-1) continue;
        // 如果现在要生小老鼠 
        if (!rat[i].multi)
        {
            rat[i].move=1;rat[i].multi=-1;
            // 两个性别只处理一个 
            if (rat[i].sex) continue;
            int x=rat[i].x,y=rat[i].y;
            for (int j=0;j<4;++j)
                if (loc[x][y]&trans[j])
                {
                    ++tot;
                    rat[tot].x=x,rat[tot].y=y;
                    rat[tot].dir=j;
                    // 南北是雄性,东西是雌性 
                    if (j&1) rat[tot].sex=1;
                    else rat[tot].sex=0;
                    rat[tot].age=rat[tot].cnt=rat[tot].dead=rat[tot].re=0;
                    rat[tot].multi=rat[tot].move=-1;
                }
        }
    }
}
int Dis(RAT a,GUN b)
{
    return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
void Attack(GUN now)
{
    switch (now.type)
    {
        // 强力炸弹 
        case 1:
            {
                memset(vis,0,sizeof(vis));
                int x,y,cnt;
                x=now.x,y=now.y;cnt=0;vis[x][y]=1;
                while ((loc[x][y]&1)&&cnt1;
                }
                x=now.x,y=now.y;cnt=0;
                while ((loc[x][y]&2)&&cnt1; 
                }
                x=now.x,y=now.y;cnt=0;
                while ((loc[x][y]&4)&&cnt1; 
                }
                x=now.x,y=now.y;cnt=0;
                while ((loc[x][y]&8)&&cnt1; 
                }
                for (int i=1;i<=tot;++i)
                    if (vis[rat[i].x][rat[i].y])
                        rat[i].dead=1;
                break;
            }
        // 神秘射线 
        case 2:
            {
                for (int i=1;i<=tot;++i)
                    if (!rat[i].dead&&Dis(rat[i],now)<=R*R)
                         rat[i].re+=3;
                break;
            }
        // 定时炸弹 
        case 3:
            {
                for (int i=1;i<=tot;++i)
                    if (rat[i].x==now.x&&rat[i].y==now.y)
                        rat[i].dead=1;
                break;
            }
        // 生物炸弹 
        case 4:
            {
                for (int i=1;i<=tot;++i)
                    if (rat[i].x==now.x&&rat[i].y==now.y)
                        rat[i].sex^=1;
                break;
            }
    }
}
void CheckDeath()
{
    int now=0;
    for (int i=1;i<=tot;++i)
        if (!rat[i].dead) bag[++now]=rat[i];
    tot=now;
    for (int i=1;i<=tot;++i) rat[i]=bag[i];
}
void Move()
{
    for (int i=1;i<=tot;++i)
    {
        // 如果 未恢复生理活动 或者 处于繁殖完的休息 或者 在繁殖中 都不能移动 
        if (rat[i].re||rat[i].move>0||rat[i].multi!=-1) continue;
        int x=rat[i].x,y=rat[i].y;
        int d=rat[i].dir,dl=(d-1+4)%4,dr=(d+1)%4,db=(d+2)%4;
        // 只要前方有管道 
        if (loc[x][y]&trans[d])
        {
            rat[i].x=x+dx[d],rat[i].y=y+dy[d];
            continue;
        }
        // 两边都有路 
        if ((loc[x][y]&trans[dl])&&(loc[x][y]&trans[dr]))
        {
            ++rat[i].cnt;
            if (rat[i].cnt&1) rat[i].dir=dl;
            else rat[i].dir=dr;
            continue;
        }
        // 左边有管道右边无管道 
        if ((loc[x][y]&trans[dl])&&((loc[x][y]&trans[dr])==0))
        {
            rat[i].dir=dl;
            continue;
        }
        // 右边有管道左边无管道 
        if ((loc[x][y]&trans[dr])&&((loc[x][y]&trans[dl])==0))
        {
            rat[i].dir=dr;
            continue;
        }
        // 死路 向右转 
        rat[i].dir=dr;
    }
}
void Arrange()
{
    for (int i=1;i<=tot;++i)
    {
        if (!rat[i].re) ++rat[i].age;
        if (!rat[i].re&&rat[i].multi!=-1) --rat[i].multi;
        if (!rat[i].re&&rat[i].move!=-1) --rat[i].move;
        if (rat[i].re) --rat[i].re;
    }
}
int main()
{
    scanf("%d%d%d%d",&L,&R,&n,&m);
    for (int i=1;i<=n;++i)
        for (int j=1;j<=m;++j) scanf("%d",&loc[i][j]);
    scanf("%d\n",&tot);
    for (int i=1;i<=tot;++i)
    {
        char c1,c2;
        scanf("%d %d %c %c\n",&rat[i].x,&rat[i].y,&c1,&c2);
        switch (c1)
        {
            case 'N':rat[i].dir=0;break;
            case 'E':rat[i].dir=1;break;
            case 'S':rat[i].dir=2;break;
            case 'W':rat[i].dir=3;break;
        }
        if (c2=='X') rat[i].sex=0;
        else rat[i].sex=1;
        rat[i].cnt=rat[i].re=rat[i].dead=0; 
        rat[i].multi=rat[i].move=-1;rat[i].age=5; 
    }
    scanf("%d%d",&P,&limit);
    for (int i=1;i<=P;++i)
    {
        scanf("%d%d%d%d",&gun[i].type,&gun[i].t,&gun[i].x,&gun[i].y);
        if (gun[i].type==3) gun[i].t+=3;
    }
    sort(gun+1,gun+P+1);
    scanf("%d",&T);now=1; 
    for (int i=0;i<=T;++i)
    {
        // start the second

        // 老鼠进行繁殖
        Multi();

        // 放置武器,攻击老鼠
        while (now<=P&&gun[now].t<=i)
        {
            Attack(gun[now]);
            ++now;
        }
        CheckDeath();
        if (tot>limit)
        {
            plague=1;
            break;
        }

        // 老鼠进行移动
        Move();

        // end the second
        Arrange();
    }
    if (plague) puts("-1");
    else printf("%d\n",tot);
}

你可能感兴趣的:(题解,模拟)