Description

  最近,佳佳迷上了一款好玩的小游戏:antbuster。游戏规则非常简单:在一张地图上,左上角是蚂蚁窝,右
下角是蛋糕,蚂蚁会源源不断地从窝里爬出来,试图把蛋糕搬回蚂蚁窝。而你的任务,就是用原始资金以及杀蚂蚁
获得的奖金造防御塔,杀掉这些试图跟你抢蛋糕的蚂蚁~下附一张游戏截图:

  为了拿到尽可能高的分数,佳佳设计了很多种造塔的方案,但在尝试了其中的一小部分后,佳佳发现,这个游
戏实在是太费时间了。为了节省时间,佳佳决定写个程序,对于每一种方案,模拟游戏进程,根据效果来判断方案
的优劣。根据自己在游戏中积累的一些经验,以及上网搜到的一些参数,佳佳猜了蚂蚁爬行的算法,并且假设游戏
中的蚂蚁也是按这个规则选择路线:1、每一秒钟开始的时候,蚂蚁都在平面中的某个整点上。如果蚂蚁没有扛着
蛋糕,它会在该点留下2单位的信息素,否则它会留下5单位的信息素。然后蚂蚁会在正北、正南、正东、正西四个
方向中选择一个爬过去。2、选择方向的规则是:首先,爬完一个单位长度后到达的那个点上,不能有其他蚂蚁或
是防御塔,并且那个点不能是蚂蚁上一秒所在的点(除非上一个时刻蚂蚁就被卡住,且这个时刻它仍无法动),当
然,蚂蚁也不会爬出地图的边界(我们定义这些点为不可达点)。如果此时有多个选择,蚂蚁会选择信息素最多的
那个点爬过去。3、如果此时仍有多种选择,蚂蚁先面向正东,如果正东不是可选择的某个方向,它会顺时针转90
°,再次判断,如果还不是,再转90°...直到找到可以去的方向。4、如果将每只蚂蚁在洞口出现的时间作为它的
活动时间的第1秒,那么每当这只蚂蚁的活动时间秒数为5的倍数的时候,它先按规则1~3确定一个方向,面对该方
向后逆时针转90°,若它沿当前方向会走到一个不可达点,它会不停地每次逆时针转90°,直到它面对着一个可达
的点,这样定下的方向才是蚂蚁最终要爬去的方向。5、如果蚂蚁的四周都是不可达点,那么蚂蚁在这一秒内会选
择停留在当前点。下一秒判断移动方向时,它上一秒所在点为其当前停留的点。6、你可以认为蚂蚁在选定方向后
,瞬间移动到它的目标点,这一秒钟剩下的时间里,它就停留在目标点。7、蚂蚁按出生的顺序移动,出生得比较
早的蚂蚁先移动。然后,是一些有关地图的信息:1、 每一秒,地图所有点上的信息素会损失1单位,如果那个点
上有信息素的话。2、 地图上某些地方是炮台。炮台的坐标在输入中给出。3、 地图的长、宽在输入中给出,对于
n * m的地图,它的左上角坐标为(0,0),右下角坐标为(n,m)。蚂蚁洞的位置为(0,0),蛋糕的位置为(n
,m)。4、 你可以把蚂蚁看做一个直径为1单位的圆,圆心位于蚂蚁所在的整点。5、 游戏开始时,地图上没有蚂
蚁,每个点上的信息素含量均为0。一些有关炮塔的信息:1、 炮塔被放置在地图上的整点处。2、 为了简单一些
,我们认为这些炮塔都是激光塔。激光塔的射速是1秒/次,它的攻击伤害为d/次,攻击范围为r。你可以认为每秒
蚂蚁移动完毕后,塔才开始攻击。并且,只有当代表蚂蚁的圆的圆心与塔的直线距离不超过r时,塔才算打得到那
只蚂蚁。3、 如果一只蚂蚁扛着蛋糕,那么它会成为target,也就是说,任何打得到它的塔的炮口都会对准它。如
果蛋糕好好地呆在原位,那么每个塔都会挑离它最近的蚂蚁进行攻击,如果有多只蚂蚁,它会选出生较早的一只。
4、 激光塔有个比较奇怪的特性:它在选定了打击目标后,只要目标在其射程内,塔到目标蚂蚁圆心的连线上的所
有蚂蚁(这里“被打到”的判定变成了表示激光的线段与表示蚂蚁的圆有公共点)都会被打到并损d格血,但激光
不会穿透它的打击目标打到后面的蚂蚁。5、 尽管在真实游戏中,塔是可以升级的,但在这里我们认为塔的布局和
等级就此定了下来,不再变动。再介绍一下蚂蚁窝:1、 如果地图上的蚂蚁不足6只,并且洞口没有蚂蚁,那么窝
中每秒会爬出一只蚂蚁,直到地图上的蚂蚁数为6只。2、 刚出生的蚂蚁站在洞口。3、 每只蚂蚁有一个级别,级
别决定了蚂蚁的血量,级别为k的蚂蚁的血量为int(4*1.1^k)(int(x)表示对x取下整)。每被塔打一次,蚂蚁的血
减少d。注意,血量为0的蚂蚁仍能精力充沛地四处乱爬,只有一只蚂蚁的血被打成负数时,它才算挂了。 4、 蚂
蚁的级别是这样算的:前6只出生的蚂蚁是1级,第7~12只是2级,依此类推。最后给出关于蛋糕的介绍:1、 简单
起见,你可以认为此时只剩最后一块蛋糕了。如果有蚂蚁走到蛋糕的位置,并且此时蛋糕没有被扛走,那么这只蚂
蚁就扛上了蛋糕。蚂蚁被打死后蛋糕归位。2、 如果一只扛着蛋糕的蚂蚁走到蚂蚁窝的位置,我们就认为蚂蚁成功
抢到了蛋糕,游戏结束。3、 蚂蚁扛上蛋糕时,血量会增加int(该蚂蚁出生时血量 / 2),但不会超过上限。整
理一下1秒钟内发生的事件: 1秒的最初,如果地图上蚂蚁数不足6,一只蚂蚁就会在洞口出生。接着,蚂蚁们在自
己所在点留下一些信息素后,考虑移动。先出生的蚂蚁先移动。移动完毕后,如果有蚂蚁在蛋糕的位置上并且蛋糕
没被拿走,它把蛋糕扛上,血量增加,并在这时被所有塔设成target。然后所有塔同时开始攻击。如果攻击结束后
那只扛着蛋糕的蚂蚁挂了,蛋糕瞬间归位。攻击结束后,如果发现扛蛋糕的蚂蚁没死并在窝的位置,就认为蚂蚁抢
到了蛋糕。游戏也在此时结束。最后,地图上所有点的信息素损失1单位。所有蚂蚁的年龄加1。漫长的1秒到此结
束。

Input

  输入的第一行是2个用空格隔开的整数,n、m,分别表示了地图的长和宽。第二行是3个用空格隔开的整数,s
、d、r,依次表示炮塔的个数、单次攻击伤害以及攻击范围。接下来s行,每行是2个用空格隔开的整数x、y,描述
了一个炮塔的位置。当然,蚂蚁窝的洞口以及蛋糕所在的位置上一定没有炮塔。最后一行是一个正整数t,表示我
们模拟游戏的前t秒钟1 < =  n,m < =  8,s < =  20,t < =  200,000

Output

  如果在第t秒或之前蚂蚁抢到了蛋糕,输出一行“Game over after x seconds”,其中x为游戏结束的时间,
否则输出“The game is going on”。如果游戏在t秒或之前结束,输出游戏结束时所有蚂蚁的信息,否则输出t秒
后所有蚂蚁的信息。格式如下:第一行是1个整数s,表示此时活着的蚂蚁的总数。接下来s行,每行5个整数,依次
表示一只蚂蚁的年龄(单位为秒)、等级、当前血量,以及在地图上的位置(a,b)。输出按蚂蚁的年龄递减排序

Sample Input

8 8
2 10 1
7 8
8 6
5

Sample Output

The game is going on
5
5 1 4 1 4
4 1 4 0 4
3 1 4 0 3
2 1 4 0 2
1 1 4 0 1
样例说明:
  3*5的地图,有1个单次伤害为1、攻击范围为2的激光炮塔,它的位置为(2,2),模拟游戏的前5秒。5秒内有
5只蚂蚁出生,都是向东爬行,其中第1~4只在路过(0,2)点时被激光塔伤了1格血。在第5秒的时候,最早出生的
蚂蚁按移动规则1~3本来该向东移动,但由于规则4的作用,它在发现向北和向西移动都会到达不可达点后,最终选
择了向南移动。

HINT

一个好的题面版本: JudgeOnline/upload/201803/1033.rar

Solution

调了一晚上的sb模拟……

Code

 #include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std; int n,m,s,d,r,T,x[],y[];//题意描述变量
int vis[][];//当前点是否有蚂蚁
int Map[][];//信息素
int dx[]={,,,,-},dy[]={,,,-,};//顺时针
double k=1.1; int kth,now_level=;//存储等级
bool Cake;//蛋糕是否被拿走
int Finish,Finish_time;//游戏是否完成以及完成时间 int Ant_num;
struct ANT
{
int level,birth,x,y,HP,start_HP,last_dir,target;
//等级,出生时间,横纵坐标,当前血量,初始血量,上一次来的方向,是否是target
bool operator < (const ANT &a) const {return birth<a.birth;} }Ant[]; bool check(int x,int y)//判断是否越界
{
if (x< || x>n || y< || y>m || vis[x][y]) return false;
return true;
} double Dis(double x,double y,double a,double b)//算两点间距离
{
return sqrt((x-a)*(x-a)+(y-b)*(y-b));
} bool In_Line(ANT a,int a1,int b1,int a2,int b2)//判断点是否在线段上
{
if (a1==a2) return a.x==a1 && a.y>min(b1,b2) && a.y<max(b1,b2);
if (a.y>max(b1,b2) || a.y<min(b1,b2)) return false;
if (a.x>max(a1,a2) || a.x<min(a1,a2)) return false;
double k=(b1-b2)*1.0/(a1-a2), b=b1-k*a1;
double h=fabs(a.y-k*a.x-b);
return h*abs(a1-a2)/Dis(a1,b1,a2,b2)<=0.5;
} int main()
{
scanf("%d%d%d%d%d",&n,&m,&s,&d,&r);
for (int i=; i<=s; ++i)
{
scanf("%d%d",&x[i],&y[i]);
vis[x[i]][y[i]]=true;
}
scanf("%d",&T);
for (int t=; t<=T; ++t)
{
if (Ant_num< && !vis[][])//产生新蚂蚁
{
Ant_num++;
kth++;
if (kth==)
{
kth=;
k*=1.1;
now_level++;
}
Ant[Ant_num].level=now_level;
Ant[Ant_num].birth=t;
Ant[Ant_num].x=; Ant[Ant_num].y=;
Ant[Ant_num].HP=Ant[Ant_num].start_HP=(int)(k*);
Ant[Ant_num].last_dir=-;
Ant[Ant_num].target=false;
vis[][]=true;
}
sort(Ant+,Ant+Ant_num+);//按出生时间排序
for (int i=; i<=Ant_num; ++i)//留下信息素
Map[Ant[i].x][Ant[i].y]+=Ant[i].target?:;
for (int i=; i<=Ant_num; ++i)
{
int maxn=-;
for (int j=; j<=; ++j)//四个方向找信息素最大的
{
int xx=Ant[i].x+dx[j],yy=Ant[i].y+dy[j];
if (!check(xx,yy) || j==Ant[i].last_dir) continue;
maxn=max(maxn,Map[xx][yy]);
}
if (maxn==-)//没有可达点
{
Ant[i].last_dir=-;
continue;
}
int direction;
for (int j=; j<=; ++j)//找下步的方向
{
int xx=Ant[i].x+dx[j],yy=Ant[i].y+dy[j];
if (!check(xx,yy) || j==Ant[i].last_dir) continue;
if (Map[xx][yy]==maxn)
{
direction=j;
break;
}
}
if ((t-Ant[i].birth+)%==)//如果是5的倍数就逆时针转
{
int nxt;
for (int j=; j<=; ++j)
{
nxt=((direction-j)%+)%+;
int xx=Ant[i].x+dx[nxt],yy=Ant[i].y+dy[nxt];
if (check(xx,yy) && nxt!=Ant[i].last_dir) break;
}
direction=nxt;
}
vis[Ant[i].x][Ant[i].y]=false;
Ant[i].x=Ant[i].x+dx[direction];
Ant[i].y=Ant[i].y+dy[direction];
if (direction== || direction==) Ant[i].last_dir=direction+;
else Ant[i].last_dir=direction-;
vis[Ant[i].x][Ant[i].y]=true;
}
for (int i=; i<=Ant_num; ++i)
if (Ant[i].x==n && Ant[i].y==m && !Cake)
{
Cake=true;//蛋糕被拿走
Ant[i].target=true;
Ant[i].HP=min(Ant[i].start_HP,Ant[i].HP+Ant[i].start_HP/);
}
for (int i=; i<=s; ++i)//炮塔是统一开火而不是按顺序依次来
{
double minn=1e16;//找最近的蚂蚁
int tar=-;//要打的目标
for (int j=; j<=Ant_num; ++j)
{
double dis=Dis(x[i],y[i],Ant[j].x,Ant[j].y);
if (r<dis) continue;//QAQ
if (Ant[j].target)
minn=-1e16,tar=j;
else if (dis<minn)
minn=dis,tar=j;
}
if (tar==-) continue;
Ant[tar].HP-=d;
for (int j=; j<=Ant_num; ++j)
if (j!=tar && In_Line(Ant[j],x[i],y[i],Ant[tar].x,Ant[tar].y))
Ant[j].HP-=d;
}
for (int i=; i<=Ant_num; ++i)
if (Ant[i].HP<)
{
vis[Ant[i].x][Ant[i].y]=false;
if (Ant[i].target) Cake=false;
for (int j=i; j<=Ant_num-; ++j)
Ant[j]=Ant[j+];
Ant_num--; i--;
}
for (int i=; i<=Ant_num; ++i)
if (Ant[i].target && Ant[i].x== && Ant[i].y==)
{
Finish=true; Finish_time=t;
break;
}
if (Finish) break;
for (int i=; i<=n; ++i)
for (int j=; j<=m; ++j)
Map[i][j]=max(,Map[i][j]-); //每秒信息素减1
}
if (Finish)
printf("Game over after %d seconds\n",Finish_time);
else
printf("The game is going on\n"),Finish_time=T;
printf("%d\n",Ant_num);
for (int i=; i<=Ant_num; ++i)
printf("%d %d %d %d %d\n",Finish_time-Ant[i].birth+-Finish,Ant[i].level,Ant[i].HP,Ant[i].x,Ant[i].y);
}

BZOJ1033:[ZJOI2008]杀蚂蚁antbuster(模拟)的更多相关文章

  1. bzoj千题计划121:bzoj1033: [ZJOI2008]杀蚂蚁antbuster

    http://www.lydsy.com/JudgeOnline/problem.php?id=1033 经半个下午+一个晚上+半个晚上 的 昏天黑地调代码 最终成果: codevs.洛谷.tyvj上 ...

  2. [bzoj1033] [ZJOI2008]杀蚂蚁antbuster

    Description 最近,佳佳迷上了一款好玩的小游戏:antbuster.游戏规则非常简单:在一张地图上,左上角是蚂蚁窝,右下角是蛋糕,蚂蚁会源源不断地从窝里爬出来,试图把蛋糕搬回蚂蚁窝.而你的任 ...

  3. BZOJ 1033: [ZJOI2008]杀蚂蚁antbuster(模拟)

    坑爹的模拟题QAQ DEBUG多了1kb QAQ 按题意做就行了 注意理解题意啊啊啊啊 尼玛输出忘换行wa了3次QAQ CODE: #include<cstdio>#include< ...

  4. [BZOJ 1033][ZJOI2008]杀蚂蚁antbuster

    1033: [ZJOI2008]杀蚂蚁antbuster Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1200  Solved: 507[Submi ...

  5. [ZJOI2008]杀蚂蚁antbuster

    [ZJOI2008]杀蚂蚁antbuster 题目 最近,佳佳迷上了一款好玩的小游戏:antbuster.游戏规则非常简单:在一张地图上,左上角是蚂蚁窝,右下角是蛋糕,蚂蚁会源源不断地从窝里爬出来,试 ...

  6. P2586 [ZJOI2008]杀蚂蚁(模拟)

    P2586 [ZJOI2008]杀蚂蚁 大模拟. 什么都不想补了. 看变量名感性理解吧 #include<iostream> #include<cstdio> #include ...

  7. 【BZOJ 1033】 [ZJOI2008]杀蚂蚁antbuster

    Description 最近,佳佳迷上了一款好玩的小游戏:antbuster.游戏规则非常简单:在一张地图上,左上角是蚂蚁窝,右下角是蛋糕,蚂蚁会源源不断地从窝里爬出来,试图把蛋糕搬回蚂蚁窝.而你的任 ...

  8. [ZJOI2008]杀蚂蚁antbuster 题解

    一个题目的可读版本:https://www.zybuluo.com/Jerusalem/note/221811 这两天做的又一道大模拟题,感觉这玩意有毒,会上瘾啊…… 比起猪国杀这道题真心不知道高到哪 ...

  9. [BZOJ 1033] [ZJOI2008] 杀蚂蚁antbuster 【模拟!】

    题目链接: BZOJ - 1033 题目分析 模拟!纯粹按照题目描述模拟! 这是一道喜闻乐见的经典模拟题! 我一共写了2遍,Debug 历时2天的所有晚自习 ... 时间超过 8h ... 我真是太弱 ...

随机推荐

  1. PIE SDK栅格图层渲染变化事件监听

    1. 功能简介 通过PIE SDK加载图层后,会默认的赋值给数据一个渲染.当用户重新给数据赋值Render或改变数据显示效果时,会触发渲染变化事件. 所谓的事件监听是在事件触发时,将执行用户指定的函数 ...

  2. esper(4-5)- Context 条件

    条件主要包含:Filter,Pattern,Crontab以及Time Period Filter主要就是对属性值的过滤,比如: create context NewUser partition by ...

  3. 学习总结——docker

    1.docker 配置 docker 安装 docker 修改默认存储位置 docker 命令详解(run篇) docker 命令详解(cp篇) 2.docker 镜像相关资料 docker 把容器c ...

  4. MHA 高可用架构部署

    一, MHA 介绍 MHA(Master High Availability)目前在MySQL高可用方面是一个相对成熟的解决方案,它由日本DeNA公司youshimaton(现就职于Facebook公 ...

  5. Hadoop Ecosystem related ports

    本文总结了Hadoop生态系统中各个组件使用的端口,包括了HDFS,Map Reduce,HBase,Hive,Spark,WebHCat,Impala,Alluxio,Sqoop等,后续会持续更新. ...

  6. Apache Beam的API设计

    不多说,直接上干货! Apache Beam的API设计 Apache Beam还在开发之中,后续对应的API设计可能会有所变化,不过从当前版本来看,基于对数据处理领域对象的抽象,API的设计风格大量 ...

  7. javascript中for in与in的用法

    1.For...In 声明用于对数组或者对象的属性进行循环/迭代操作. 对于数组 ,迭代出来的是数组元 素,对于对象 ,迭代出来的是对象的属性: var x var mycars = new Arra ...

  8. http状态代码含义收藏

    状态代码(也称作错误代码),指为服务器所接收每个请求(网页点击)分配的 3 位数代码.多数有效网页点击都有状态代码 200("正常")."网页未找到"错误会生产 ...

  9. Class.forName和ClassLoader的区别

    一 看名字就知道了,一个是类的创建,一个类加载器 二 再看下Class.forName源码,调用了ClassLoader @CallerSensitive public static Class< ...

  10. bzoj 5084: hashit

    Description 你有一个字符串S,一开始为空串,要求支持两种操作 在S后面加入字母C 删除S最后一个字母 问每次操作后S有多少个两两不同的连续子串 Solution 先忽略删除操作,建出最终的 ...