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;
    }
    
  • 相关阅读:
    Python 用 matplotlib 中的 plot 画图
    python--serial串口通信
    verilog,vhdl,bdf文件一起综合
    项目小笔记2--qt designer 修改字体,部件拖入layout,引用time模块延时,正则表达式判断输入,进制转换,部件固定大小,graphics view显示图片,消息提示框使用
    虚拟环境下通过pyinstaller 打包
    FPGA--IIC通信
    FPGA--SPI通信
    verilog 语法
    【C_Language】---队列和栈的C程序实现
    【C_Language】---C文件学习
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7626535.html
Copyright © 2011-2022 走看看