您的位置:首页 > 其它

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

2017-03-06 20:05 549 查看

题目描述

传送门

题解

又是一道大模拟。。。

需要注意的几个地方:

1、一个时刻x+时间单位x~y操作的顺序是:时刻x老鼠繁殖、时刻x放武器、判断是否发生鼠疫、时间单位x~y老鼠移动。

2、只有某一个点上有且仅有两只老鼠并且满足性别互异、均成年、不在上一次繁殖期间或者昏迷状态下才可以繁殖。

3、某一次繁殖结束之后(等待+繁殖+休息),如果两只老鼠又进行了一次操作(走一步或者转一下方向),并且又同时到了同一个点上,那么它们可以接着繁殖。

4、在昏迷过程中,所有的生理活动都被暂停,包括:年龄增长、繁殖或休息的时间。

5、在繁殖过程中(等待+繁殖+休息)都不能移动。

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
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 t<a.t;
}
}gun[105];
// 目前的老鼠总数
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)&&cnt<L)
{
--x;++cnt;
vis[x][y]=1;
}
x=now.x,y=now.y;cnt=0;
while ((loc[x][y]&2)&&cnt<L)
{
++y;++cnt;
vis[x][y]=1;
}
x=now.x,y=now.y;cnt=0;
while ((loc[x][y]&4)&&cnt<L)
{
++x;++cnt;
vis[x][y]=1;
}
x=now.x,y=now.y;cnt=0;
while ((loc[x][y]&8)&&cnt<L)
{
--y;++cnt;
vis[x][y]=1;
}
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);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: