zoukankan      html  css  js  c++  java
  • P2586 [ZJOI2008]杀蚂蚁

    传送门

    快乐模拟,修身养性

    代码长度其实还好,主要是细节多

    只要知道一些计算几何基础知识即可快乐模拟,按着题目要求一步步实现就行啦

    注意仔细读题,蚂蚁每 $5$ 秒乱走一次的时候是只要能走就走了,不一定要信息素最多

    还有因为炮台是同时打的,所以目标要提前选好,就算某只蚂蚁被打成负血了,还是会继续被打

    蚂蚁初始年龄为 $0$,活动时间是按 $1$ 开始的(看样例就懂了)

    我用 $set$ 按年龄维护蚂蚁信息,注意枚举 $set$ 内的蚂蚁时要先把 $set$ 的信息统一取出,不然可能会指针越界

    把取出后修改的信息再重新放回 $set$ 即可,具体模拟实现当然还是看代码啦,当然最好还是自己写一遍,$std$ 拿来对拍比较好

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<set>
    using namespace std;
    typedef long long ll;
    typedef double db;
    inline int read()
    {
        int x=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
        while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
        return x*f;
    }
    const db eps=1e-6;
    const int N=233,xx[4]={0,1,0,-1},yy[4]={1,0,-1,0};
    inline int dcmp(db x) { if(fabs(x)<eps) return 0; return x<0 ? -1 : 1; }
    int n,m,S,attack,R,T,ant_cnt;
    //矩阵长宽,炮台数量,攻击,半径,时间,目前蚂蚁数量
    int Map[N][N],Vis[N][N];
    //维护地图信息素,维护地图被占用的位置
    bool Cake=1,GG;//是否有蛋糕,游戏是否结束
    struct Point {
        int x,y;
        Point (int a=0,int b=0) { x=a,y=b; }
        inline bool operator == (const Point &tmp) const { return x==tmp.x&&y==tmp.y; }
        inline Point operator - (const Point &tmp) const { return Point(x-tmp.x,y-tmp.y); }
        inline Point to(int k) { return Point(x+xx[k],y+yy[k]); }
    };
    inline db Cross(Point A,Point B) { return A.x*B.y-A.y*B.x; }
    inline db Dot(Point A,Point B) { return A.x*B.x+A.y*B.y; }
    inline db Len(Point A) { return sqrt(Dot(A,A)); }
    //以上计算几何板子
    inline bool pd(Point P) { return P.x<0||P.x>n||P.y<0||P.y>m||Vis[P.x][P.y]; }//判断位置合法性
    struct Ant {//蚂蚁信息
        int blood,age,mxbld,lev;
        //当前血量,年龄,最大生命,等级
        bool target; Point P,pre;
        //是否有蛋糕,当前位置,上一步的位置
        Ant (int c=0,int d=0,int e=0,int f=0,bool h=0,Point A=Point(0,0),Point B=Point(0,0)) {
            blood=c,age=d,mxbld=e,lev=f,target=h; P=A; pre=B;
        }
        void Move()//进行移动
        {
            int X[5],tot=0,mx=0; Vis[P.x][P.y]=0;//原本位置蚂蚁走了
            for(int i=0;i<4;i++)//按方向枚举
            {
                Point t=P.to(i);
                if(pd(t)||t==pre||(tot && Map[t.x][t.y]<mx)) continue;//判断不合法
                if(Map[t.x][t.y]>mx) mx=Map[t.x][t.y],tot=0;//修改合法方向
                X[++tot]=i;
            }
            if(!tot) { pre=P; Vis[P.x][P.y]=1; return; }//判断不可走
            if((age+1)%5) { pre=P; P=P.to(X[1]); Vis[P.x][P.y]=1; return ; }//正常移动
            for(int k=(X[1]+3)%4,i=0;i<4;i++,k=(k+3)%4)//5秒乱走一次
            {
                Point t=P.to(k);
                if(!pd(t)&&!(t==pre))//只要可以走就直接走了
                    { pre=P,P=t,Vis[P.x][P.y]=1; return; }
            }
        }
        void try_to_get_cake()//看看能不能得到蛋糕
        {
            if(P.x!=n||P.y!=m||!Cake) return;
            Cake=0; blood=min(mxbld,blood+(mxbld/2)); target=1;
            //得到蛋糕,更新数据
        }
        inline bool operator < (const Ant &tmp) const { return age>tmp.age; }//按年龄排序
    }tmp[N];
    int tot;//tmp的右端点
    set <Ant> ant;
    inline db Dis(Point P,Point Q,Point A)
    {
        if(dcmp(Dot(A-P,Q-P))<0) return Len(A-P);
        if(dcmp(Dot(A-Q,P-Q))<0) return Len(A-Q);
        return fabs(Cross(A-P,Q-P)/Len(Q-P));
    }//同样计算几何板子,求A到线段PQ的距离
    struct turret {//炮台
        Point P;//坐标
        void Attack()//进行攻击
        {
            Ant to,A; db mi=N;
            for(int i=1;i<=tot;i++)
            {
                A=tmp[i];
                if(Len(P-A.P)>1.0*R+eps) continue;//太远就没得打
                if(A.target) { to=A; mi=0; break; }//发现有target
                if(Len(P-A.P)+eps<mi) to=A,mi=Len(P-A.P);//找到最近的蚂蚁
            }
            if(int(mi+eps)==N) return;//范围内没有目标
            for(int i=1;i<=tot;i++)
                if(Dis(P,to.P,tmp[i].P)<0.5+eps) tmp[i].blood-=attack;//看看能否波及到其他蚂蚁
        }
    }Tur[N];
    inline db ksm(db x,int y)
    {
        db res=1;
        while(y) { if(y&1) res=res*x; x=x*x; y>>=1; }
        return res;
    }
    int cnt;//总共出现的蚂蚁数量
    void Work()
    {
        if(ant_cnt<6&&!Vis[0][0])//当前位置没有蚂蚁才能刷蚂蚁
        {
            Ant New_ant; New_ant.lev=cnt/6+1;
            New_ant.blood=New_ant.mxbld=4.0*ksm(1.1,New_ant.lev);
            New_ant.P=Point(0,0); Vis[0][0]=1;
            ant_cnt++; cnt++; ant.insert(New_ant);//更新一堆数据
        }
        for(auto A: ant)//更新地图信息素
        {
            if(!A.target) Map[A.P.x][A.P.y]+=2;
            else Map[A.P.x][A.P.y]+=5;
        }
        tot=0; for(auto A: ant) tmp[++tot]=A;//取出数据
        for(int i=1;i<=tot;i++)
        {
            ant.erase(tmp[i]),tmp[i].Move();
            tmp[i].try_to_get_cake();//移动并判断得到蛋糕
        }
        for(int i=1;i<=S;i++) Tur[i].Attack();//炮台攻击
        for(int i=1;i<=tot;i++)
        {
            if(tmp[i].blood>=0) ant.insert(tmp[i]);//最后统一插回set
            else { ant_cnt--; Vis[tmp[i].P.x][tmp[i].P.y]=0; if(tmp[i].target) Cake=1; }
            //蚂蚁死了,更新数据,归还蛋糕
        }
        for(auto A: ant) if(A.target&&!A.P.x&&!A.P.y) { GG=1; return; }//判断游戏结束
        for(int i=0;i<=n;i++)
            for(int j=0;j<=m;j++) if(Map[i][j]) Map[i][j]--;//更新信息素
        tot=0; for(auto A: ant) tmp[++tot]=A;
        for(int i=1;i<=tot;i++) ant.erase(tmp[i]),tmp[i].age++;//统一年龄加1
        for(int i=1;i<=tot;i++) ant.insert(tmp[i]);
    }
    int main()
    {
        n=read(),m=read(); S=read(),attack=read(),R=read();
        for(int i=1;i<=S;i++)
        {
            Tur[i].P.x=read(),Tur[i].P.y=read();
            Vis[ Tur[i].P.x ][ Tur[i].P.y ]=1;//炮台不能走
        }
        int Time=read();
        for(int t=1;t<=Time;t++)
        {
            Work();
            if(GG) { printf("Game over after %d seconds
    ",t); break; }
        }
        if(!GG) printf("The game is going on
    ");
        printf("%d
    ",int(ant.size()));
        for(auto A: ant) printf("%d %d %d %d %d
    ",A.age,A.lev,A.blood,A.P.x,A.P.y);
        return 0;
    }
  • 相关阅读:
    C# 如何生成CHM帮助文件
    Excel导出问题
    JS一些类实现方式的性能研究
    Date对象的一些相关函数
    ECMASCRIPT5新特性(转载)
    javascript apo
    $linq A Javascript LINQ library
    javascript 编程规范
    flash 工程师的标准
    flash 弹出 网页
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/11444627.html
Copyright © 2011-2022 走看看