[BZOJ1033][ZJOI2008]杀蚂蚁antbuster(大模拟)

来源:互联网 发布:suse linux和opensuse 编辑:程序博客网 时间:2024/04/30 10:53

题目描述

传送门

题解

bz的题面真心不爽,建议去codevs
比较良心的一道大模拟,题面写的比较清楚,也没有什么坑

几个需要注意的地方
1、对于每一只蚂蚁来说,年龄=秒数-1
2、选择方向的过程是:首先根据规则1-3选出一个方向,这个时候判断如果秒数不是5的倍数的话就直接走过去;如果是5的倍数就按照下一个规则继续选一个方向然后走过去。注意可达点的定义以及各种前提(先可达、再信息素最大)
3、杀死一只蚂蚁之后,需要更新:地图,当前蚂蚁数量,蛋糕
4、炮攻击的时候用计算几何的方法算点线距

剩下的严格根据题目描述和顺序就行了
具体看代码

代码

#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>#include<cmath>using namespace std;#define N 200005double eps=1e-9;int dcmp(double x){    if (x<=eps&&x>=-eps) return 0;    return (x>0)?1:-1;}struct Vector{    double x,y;    Vector(double X=0,double Y=0)    {        x=X,y=Y;    }};typedef Vector Point;Vector operator + (Vector a,Vector b) {return Vector(a.x+b.x,a.y+b.y);}Vector operator - (Vector a,Vector b) {return Vector(a.x-b.x,a.y-b.y);}bool operator == (Vector a,Vector b) {return a.x==b.x&&a.y==b.y;}double Dot(Vector a,Vector b){    return a.x*b.x+a.y*b.y;}double Cross(Vector a,Vector b){    return a.x*b.y-a.y*b.x;}double Len(Vector a){    return sqrt(a.x*a.x+a.y*a.y);}double DisTS(Point P,Point A,Point B){    if (A==B) return Len(P-A);    Vector v=B-A,w=P-A,u=P-B;    if (dcmp(Dot(v,w))<0) return Len(w);    else if (dcmp(Dot(v,u))>0) return Len(u);    else return fabs(Cross(v,w)/Len(v));}//n,m是地图范围,guncnt为炮的个数,d为每一次攻击的血量,r为攻击半径,t为模拟时间,T为当前时间 int n,m,guncnt,d,r,t,T;//蚂蚁 struct ANT{    //当前位置,上一次的位置     int x,y,lastx,lasty;    //年龄(秒数)    int age;    //等级     int level;    //起始血量,实际血量     int startblood,blood;    //是否扛着蛋糕     bool carry;}ant[10];//炮 struct GUN{    //位置     int x,y;}gun[25];//antcnt当前蚂蚁的总数,tot所有蚂蚁的总数,cake为扛着蛋糕的蚂蚁编号 int antcnt,tot,cake;//mp是地图,为0表示什么都没有,为-1表示有炮,为正数表示有几只蚂蚁 int mp[10][10]; //infor为信息素的值int infor[10][10];//为1.1的n次方,用于算起始血量 double mi[N];//向上、左、下、右走 int dx[4]={-1,0,1,0},dy[4]={0,-1,0,1};//判断游戏是否提前结束 bool flag;void AntBirth(){    if (antcnt<6&&!mp[0][0])    {        ++antcnt;++tot;        ant[antcnt].x=ant[antcnt].y=ant[antcnt].lastx=ant[antcnt].lasty=0;        ant[antcnt].age=1;        ant[antcnt].level=(tot-1)/6+1;        ant[antcnt].startblood=ant[antcnt].blood=floor(4*mi[ant[antcnt].level]);        ant[antcnt].carry=0;        ++mp[0][0];    }}void Information(){    for (int i=1;i<=antcnt;++i)    {        if (ant[i].carry) infor[ant[i].x][ant[i].y]+=5;        else infor[ant[i].x][ant[i].y]+=2;    }}void Move(){    // 0 上 2 下 1 左 3 右     for (int i=1;i<=antcnt;++i)    {        //按照1-3的规则先选定一个方向         // x,y为这只蚂蚁当前的点,lastx,lasty为上一次来的点         int x=ant[i].x,y=ant[i].y;        int lastx=ant[i].lastx,lasty=ant[i].lasty;        // can[i]表示4个方向,向这个方向走是不是可达点         bool can[4];memset(can,0,sizeof(can));        //nxtx,nxty为下一步到达的点         //Max为可达点中信息素的最大值        //cancnt为可达点个数         int Max=0,cancnt=0;        for (int j=0;j<4;++j)        {            int nxtx=x+dx[j],nxty=y+dy[j];            if (nxtx>=0&&nxtx<=n&&nxty>=0&&nxty<=m&&mp[nxtx][nxty]==0&&(nxtx!=lastx||nxty!=lasty))            {                can[j]=1;++cancnt;                 Max=max(Max,infor[nxtx][nxty]);            }        }        if (!cancnt)        {            ant[i].lastx=x;ant[i].lasty=y;            continue;        }        int dir=0;        for (int j=3;j>=0;--j)        {            int nxtx=x+dx[j],nxty=y+dy[j];            if (can[j]&&infor[nxtx][nxty]==Max)            {                dir=j;                if (ant[i].age%5==0) break;                --mp[x][y];++mp[nxtx][nxty];                ant[i].lastx=x,ant[i].lasty=y;                ant[i].x=nxtx,ant[i].y=nxty;                 break;            }        }        //如果满足年龄是5的倍数,顺时针旋转,找到一个可达点         if (ant[i].age%5==0)        {            for (int j=0;j<4;++j)            {                ++dir;if (dir==4) dir=0;                if (can[dir])                {                    int nxtx=x+dx[dir],nxty=y+dy[dir];                    --mp[x][y];++mp[nxtx][nxty];                    ant[i].lastx=x,ant[i].lasty=y;                    ant[i].x=nxtx,ant[i].y=nxty;                    break;                }            }        }    }}void CarryCake(){    if (cake) return;    for (int i=1;i<=antcnt;++i)        if (ant[i].x==n&&ant[i].y==m)        {            ant[i].carry=1;cake=i;            //增加血量             ant[i].blood+=ant[i].startblood/2;            ant[i].blood=min(ant[i].blood,ant[i].startblood);            break;        }}int qr(int x){    return x*x;}int length(ANT a,GUN b){    return qr(a.x-b.x)+qr(a.y-b.y);}bool canhit(ANT a,GUN b,ANT c){    Point A=Point(b.x,b.y);    Point B=Point(c.x,c.y);    Point P=Point(a.x,a.y);    double dis=DisTS(P,A,B);    if (dcmp(dis-0.5)<=0) return 1;    else return 0;}void Attack(){    //length(ant,gun)表示这个蚂蚁和这个炮距离的平方     for (int i=1;i<=guncnt;++i)    {        int goal=0;        if (cake&&length(ant[cake],gun[i])<=r*r) goal=cake;        else        {            int Min=100000;            for (int j=1;j<=antcnt;++j)            {                int now=length(ant[j],gun[i]);                if (now<=r*r&&now<Min)                {                    Min=now;                    goal=j;                }            }        }        if (!goal) continue;         //canhit(i,j,k)表示i这只蚂蚁是否在j这个炮和k这个蚂蚁的连线上         for (int j=1;j<=antcnt;++j)            if (canhit(ant[j],gun[i],ant[goal])) ant[j].blood-=d;    }}void CheckDeath(){    int i=1;    while (i<=antcnt)    {        if (ant[i].blood<0)        {            --mp[ant[i].x][ant[i].y];            for (int j=i;j<antcnt;++j)                ant[j]=ant[j+1];            --antcnt;        }        else ++i;    }    cake=0;    for (int i=1;i<=antcnt;++i)        if (ant[i].carry) {cake=i;break;}}bool CheckGame(){    if (!cake) return 0;    for (int i=1;i<=antcnt;++i)        if (!ant[i].x&&!ant[i].y&&ant[i].carry) return 1;    return 0; }int main(){    scanf("%d%d",&n,&m);    scanf("%d%d%d",&guncnt,&d,&r);    for (int i=1;i<=guncnt;++i)    {        scanf("%d%d",&gun[i].x,&gun[i].y);        mp[gun[i].x][gun[i].y]=-1;    }    scanf("%d",&t);    mi[0]=1.0;for (int i=1;i<=t;++i) mi[i]=mi[i-1]*1.1;    for (T=1;T<=t;++T)    {        //start the second         // 出生一只蚂蚁          AntBirth();        // 蚂蚁留下信息素        Information();        // 将蚂蚁移动        Move();        // 蚂蚁要扛蛋糕        CarryCake();        // 炮开始攻击        Attack();        // 检查蚂蚁的死亡情况以及蛋糕是否归位        CheckDeath();        // 判断游戏是否结束         flag=CheckGame();        if (flag) break;        for (int i=0;i<=n;++i)            for (int j=0;j<=m;++j)                if (infor[i][j]) --infor[i][j];        for (int i=1;i<=antcnt;++i)            ++ant[i].age;        //end the second     }    if (flag) printf("Game over after %d seconds\n",T);    else puts("The game is going on");    printf("%d\n",antcnt);    for (int i=1;i<=antcnt;++i)        printf("%d %d %d %d %d\n",ant[i].age-1,ant[i].level,ant[i].blood,ant[i].x,ant[i].y);}
0 0
原创粉丝点击