zoukankan      html  css  js  c++  java
  • 【BZOJ 1033】 [ZJOI2008]杀蚂蚁antbuster(判断线段是否和圆相交)

    【题目链接】:http://www.lydsy.com/JudgeOnline/problem.php?id=1033

    【题意】

    https://www.zybuluo.com/Jerusalem/note/221811

    【题解】

    。。。
    模拟题。
    要用到计算几何知识;
    即求一段线段是不是和圆相交;
    如果一只蚂蚁被打死了.还要一直打才行。
    因为有一个蛋糕蚂蚁的判断。。

    【完整代码】

    #include <bits/stdc++.h>
    using namespace std;
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define LL long long
    #define rep1(i,a,b) for (int i = a;i <= b;i++)
    #define rep2(i,a,b) for (int i = a;i >= b;i--)
    #define mp make_pair
    #define pb push_back
    #define fi first
    #define se second
    #define rei(x) scanf("%d",&x)
    #define rel(x) scanf("%lld",&x)
    #define ref(x) scanf("%lf",&x)
    
    typedef pair<int, int> pii;
    typedef pair<LL, LL> pll;
    
    const int dx[9] = { 0,0,1,0,-1,-1,-1,1,1 };
    const int dy[9] = { 0,1,0,-1,0,-1,1,-1,1 };
    const double pi = acos(-1.0);
    const int MAX_PAOTA = 25;
    const int MAX_MAYI = 10;
    const int MAX_SIZE = 10;
    
    struct point
    {
        int x, y;
    };
    
    struct mayi
    {
        int x, y, id, xue, cunzai, dangao, prex, prey, age, chushi;
        void get_xue(int k)
        {
            k = ((k - 1) / 6) + 1;//通过id获取它的等级
            double t = 1;
            rep1(i, 1, k)
                t = t*1.1;//计算1.1的k次方
            t *= 4;//乘上4
            xue = int(t);//转成整数
            chushi = xue;//记录初始血量
        }
    };
    
    int n, m, s, d, r, tot, now, t;//n和m是地图的长和宽
    int tu[MAX_SIZE][MAX_SIZE];
    //tot是当前出生的蚂蚁的新id
    //now是蚂蚁的只数
    point paota[MAX_PAOTA];
    mayi mayis[MAX_MAYI];
    int can[MAX_SIZE][MAX_SIZE];
    int get_dangao;
    
    bool cmp1(mayi a, mayi b)//按照出生的顺序排
    {
        return a.id < b.id;
    }
    
    bool cmp2(mayi a, mayi b)//按年龄递减排
    {
        return a.age > b.age;
    }
    
    void in()
    {
        rei(n), rei(m);
        rei(s), rei(d), rei(r);
        rep1(i, 1, s)
        {
            rei(paota[i].x), rei(paota[i].y);
            can[paota[i].x][paota[i].y] = 0;
        }
        rei(t);
    }
    
    int kong()
    {
        rep1(i, 1, 6)
            if (mayis[i].cunzai == 0)
                return i;
        return 233;
    }
    
    void xinxi()
    {
        rep1(i, 1, 6)
            if (mayis[i].cunzai)//如果有蚂蚁
            {
                int x = mayis[i].x, y = mayis[i].y;//
                if (mayis[i].dangao)//如果这只蚂蚁身上有蛋糕就信息素加5
                    tu[x][y] += 5;
                else//否则加2
                    tu[x][y] += 2;
            }
    }
    
    bool is(int x, int y)//判断这个点是不是蛋糕所在的点
    {
        return (x == n && y == m);
    }
    
    int sqr(int x)
    {
        return x*x;
    }
    
    void moni()
    {
        rep1(i, 1, 6)//一开始所有的蚂蚁都不存在
            mayis[i].cunzai = 0;
        get_dangao = 0;
        rep1(T, 1, t)
        {
            if (now < 6 && can[0][0])//如果蚂蚁的个数小于6且蚂蚁窝的位置没有蚂蚁
            {
                now++;//增加一只蚂蚁
                int po = kong();//找到可以新加蚂蚁的蚂蚁数组的下标
                mayis[po].x = mayis[po].y = 0, mayis[po].cunzai = 1;//把这个蚂蚁加入
                                                                    //记录坐标为0,0然后标记这只蚂蚁存在
                mayis[po].id = ++tot, mayis[po].get_xue(tot), mayis[po].dangao = 0;
                mayis[po].prex = mayis[po].prey = -1;
                //tot是这只蚂蚁的id,即总共是第几只蚂蚁,通过这个tot能获得它的血量,然后一开始都没有蛋糕
                mayis[po].age = 0;//一开始蚂蚁的年龄是0
                can[0][0] = 0;//标记蚂蚁窝的位置有蚂蚁了
            }
            xinxi();//撒完信息素
                    //然后呢...然后移动
            sort(mayis + 1, mayis + 1 + 6, cmp1);
            //id小的先移动
            rep1(i, 1, 6)
                if (mayis[i].cunzai)//存在就可以移动
                {
                    int tot = 0;
                    int x = mayis[i].x, y = mayis[i].y, cnt = 0, maxxinxi, cntju;
                    int tarx, tary;
                    rep1(j, 1, 4)//先往4个方向找,看看有没有可以走的点
                    {
                        int tx = x + dx[j], ty = y + dy[j];
                        if (tx<0 || tx>n) continue;
                        if (ty<0 || ty>m) continue;
                        if (tx == mayis[i].prex && ty == mayis[i].prey) continue;//不能是它之前待的位置
                        if (!can[tx][ty]) continue;
                        if (cnt == 0)//顺便找信息素最大的方向
                        {
                            maxxinxi = tu[tx][ty];
                            cntju = j;//记录信息素最大的方向
                            cnt = 1;//记录只有一个
                        }
                        else
                        {
                            if (maxxinxi < tu[tx][ty])//如果信息素更大就更新
                            {
                                maxxinxi = tu[tx][ty];//
                                cntju = j;
                                cnt = 1;
                            }
                            else
                                if (maxxinxi == tu[tx][ty])//如果和最大的信息素一样就增加最大信息素的方向个数
                                    cnt++;
                        }
                        tarx = tx, tary = ty;//这是用于处理只有一个方向可以走的情况
                        tot += can[tx][ty];//记录有几个方向可以走
                    }
                    if (tot == 0)//如果没有可以走的点.那就只能待在原地了
                                 //此时是5的倍数也无所谓了
                    {
                        mayis[i].prex = x, mayis[i].prey = y;
                        if (!get_dangao && is(x, y))//可能有蛋糕此时回到了n,m的位置
                        {
                            get_dangao = 1;//获得蛋糕
                            mayis[i].xue += int(mayis[i].chushi / 2);//增加血量
                            mayis[i].xue = min(mayis[i].xue, mayis[i].chushi);//不能超过上限
                            mayis[i].dangao = 1;//记录它获得蛋糕
                        }
                    }
                    else
                        if (tot == 1)//如果只有一个确认的方向可以走
                                     //那么就算是5的倍数也是只能走这个方向
                        {
                            mayis[i].prex = x, mayis[i].prey = y;
                            can[x][y] = 1;//因为已经走开了,所以这个位置就可以走了
                            mayis[i].x = tarx, mayis[i].y = tary;//到了新的位置
                            if (!get_dangao && is(tarx, tary))//如果还没有蚂蚁拿到蛋糕且它在蛋糕位置
                            {
                                get_dangao = 1;//记录它拿到了蛋糕
                                mayis[i].xue += int(mayis[i].chushi / 2);//增加血量
                                mayis[i].xue = min(mayis[i].xue, mayis[i].chushi);//不能超过上限
                                mayis[i].dangao = 1;//记录它拿到了蛋糕
                            }
                            can[tarx][tary] = 0;//这个位置不能再走了
                        }
                        else//有多个方向可以走
                        {
                            if (cnt == 1)//如果信息量最多的那个只有一个
                            {
                                //那么方向就确定了即cntju
                                //这个时候如果是5的倍数就逆时针旋转
                                if (((mayis[i].age + 1) % 5) == 0)
                                {
                                    while (1)
                                    {
                                        cntju--;
                                        if (cntju < 1)  cntju = 4;
                                        int tx = x + dx[cntju], ty = y + dy[cntju];
                                        if (tx<0 || tx>n) continue;
                                        if (ty<0 || ty>m) continue;
                                        if ((tx == mayis[i].prex) && (ty == mayis[i].prey)) continue;
                                        if (!can[tx][ty]) continue;
                                        //找到第一个可以走的方向
                                        break;
                                    }
                                }
                                //转到了那个合适的位置了
                                mayis[i].prex = x, mayis[i].prey = y;
                                can[x][y] = 1;//走开了
                                mayis[i].x = x + dx[cntju], mayis[i].y = y + dy[cntju];//新的位置
                                if (!get_dangao && is(mayis[i].x, mayis[i].y))
                                {
                                    get_dangao = 1;
                                    mayis[i].xue += int(mayis[i].chushi / 2);
                                    mayis[i].xue = min(mayis[i].xue, mayis[i].chushi);
                                    mayis[i].dangao = 1;
                                }
                                can[x + dx[cntju]][y + dy[cntju]] = 0;//这个位置不能走了
                            }
                            else
                            {
                                //信息素没办法判断了
                                //先从正东然后 顺时针旋转转到第一个可以选择的地方
                                rep1(j, 1, 4)
                                {
                                    int tx = x + dx[j], ty = y + dy[j];
                                    if (tx<0 || tx>n) continue;
                                    if (ty<0 || ty>m) continue;
                                    if ((tx == mayis[i].prex) && (ty == mayis[i].prey)) continue;
                                    if (!can[tx][ty]) continue;
                                    if (tu[tx][ty] != maxxinxi) continue;//信息素不是最大的那个不算的。。
                                    cntju = j;
                                    break;
                                }
                                if (((mayis[i].age + 1) % 5) == 0)//这个时候如果是5的倍数就逆时针旋转
                                {
                                    while (1)
                                    {
                                        cntju--;
                                        if (cntju < 1)  cntju = 4;
                                        int tx = x + dx[cntju], ty = y + dy[cntju];
                                        if (tx<0 || tx>n) continue;
                                        if (ty<0 || ty>m) continue;
                                        if ((tx == mayis[i].prex) && (ty == mayis[i].prey)) continue;
                                        if (!can[tx][ty]) continue;
                                        break;
                                    }
                                }
                                mayis[i].prex = x, mayis[i].prey = y;
                                can[x][y] = 1;//可以走了
                                mayis[i].x = x + dx[cntju], mayis[i].y = y + dy[cntju];//到了新位置
                                if (!get_dangao && is(mayis[i].x, mayis[i].y))//到了蛋糕位置,蛋糕没被拿走
                                {
                                    get_dangao = 1;
                                    mayis[i].xue += int(mayis[i].chushi / 2);
                                    mayis[i].xue = min(mayis[i].xue, mayis[i].chushi);
                                    mayis[i].dangao = 1;
                                }
                                can[x + dx[cntju]][y + dy[cntju]] = 0;//不能走了
                            }
                        }
                }
            //蚂蚁都移动完了.塔开始攻击
            rep1(i, 1, s)
            {//i枚举每一个塔
                int which = -1, midis = -1;
                rep1(j, 1, 6)//如果有这只蚂蚁
                    if (mayis[j].cunzai)
                    {
                        int x = mayis[j].x, y = mayis[j].y;
                        int dis = sqr(x - paota[i].x) + sqr(y - paota[i].y);//获取距离平方
                        if (dis <= sqr(r))//如果在攻击范围内
                        {
                            if (mayis[j].dangao)//如果是拿着蛋糕的那只,就直接攻击它了
                            {
                                which = j;
                                midis = dis;
                                break;
                            }
                            if (midis == -1)//否则选择距离最近的那只搞
                            {
                                midis = dis;
                                which = j;
                            }
                            else
                            {
                                if (dis < midis)
                                {
                                    midis = dis;
                                    which = j;
                                }
                            }
                        }
                    }
                if (which == -1) continue;//没有一直蚂蚁能攻击到就跳过
                int x = mayis[which].x - paota[i].x, y = mayis[which].y - paota[i].y;
                int MXX = max(mayis[which].x, paota[i].x), tpx = min(mayis[which].x, paota[i].x);
                int MXY = max(mayis[which].y, paota[i].y), tpy = min(mayis[which].y, paota[i].y);
    
                rep1(j, 1, 6)//
                    if (mayis[j].cunzai)//不要忘记判断这只蚂蚁是否存在
                        if (mayis[j].x >= tpx&&mayis[j].x <= MXX&&mayis[j].y >= tpy&&mayis[j].y <= MXY
                            &&fabs((mayis[j].x - paota[i].x)*y - (mayis[j].y - paota[i].y)*x) / sqrt(x*x + y*y) <= 0.5)
                            mayis[j].xue -= d;
    
            }
            //攻击也完啦!
            rep1(j, 1, 6)
                if (mayis[j].cunzai)
                {
                    if (mayis[j].xue < 0)
                    {
                        mayis[j].cunzai = 0;
                        if (mayis[j].dangao)
                            get_dangao = 0;
                        can[mayis[j].x][mayis[j].y] = 1;
                        now--;
                    }
                }
    
            //printf("%d
    ", get_dangao);
            if (get_dangao != 0)
            {
                //如果拿着蛋糕的那只到了蚂蚁窝就结束啦
                rep1(j, 1, 6)
                    if (mayis[j].cunzai && mayis[j].dangao&& mayis[j].x == 0 && mayis[j].y == 0)
                    {
                        printf("Game over after %d seconds
    ", T);
                        return;
                    }
            }
            rep1(i, 0, n)
                rep1(j, 0, m)
                if (tu[i][j] > 0)
                    tu[i][j]--;
            rep1(i, 1, 6)
                if (mayis[i].cunzai)
                {
                    mayis[i].age++;
                }
            //if (T == 7)
            //  break;
        }
        printf("The game is going on
    ");
    }
    
    void pre()
    {
        rep1(i, 0, 9)
            rep1(j, 0, 9)
            can[i][j] = 1;
    }
    
    void o()
    {
        sort(mayis + 1, mayis + 1 + 6, cmp2);
        printf("%d
    ", now);
        rep1(i, 1, 6)
            if (mayis[i].cunzai)
                cout << mayis[i].age << ' ' << ((mayis[i].id - 1) / 6) + 1 << ' ' << mayis[i].xue << ' ' << mayis[i].x << ' ' << mayis[i].y << endl;
    }
    
    int main()
    {
        //printf("%f
    ", d_zx(point{ 0,1 }, point{ 1,0 }, point{ 0,0 }));
        //return 0;
        //freopen("F:\rush.txt", "r", stdin);
        pre();
        in();
        moni();
        o();
        //printf("
    %.2lf sec 
    ", (double)clock() / CLOCKS_PER_SEC);
        return 0;
    }
    
  • 相关阅读:
    git(1)-git关联GitHub-windows-转载
    jenkins(4)-jenkins配置邮件通知
    jenkins(3)-linux下安装jenkins(yum install方式)
    【PAT甲级】1090 Highest Price in Supply Chain (25 分)(DFS)
    【PAT甲级】1087 All Roads Lead to Rome (30 分)(MAP【int,string】,邻接表,DFS,模拟,SPFA)
    【PAT甲级】1018 Public Bike Management (30 分)(DFS,SPFA)
    Educational Codeforces Round 61 (Rated for Div. 2) G(线段树,单调栈)
    Atcoder Grand Contest 032C(欧拉回路,DFS判环)
    Educational Codeforces Round 62 (Rated for Div. 2)E(染色DP,构造,思维,组合数学)
    Atcoder Grand Contest 031C(构造,思维,异或,DFS)
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7626535.html
Copyright © 2011-2022 走看看