【BZOJ 1033】 [ZJOI2008]杀蚂蚁antbuster(判断线段是否和圆相交)
2017-10-04 18:45
567 查看
【题目链接】: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\n", 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\n", 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\n"); } 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\n", 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\n", d_zx(point{ 0,1 }, point{ 1,0 }, point{ 0,0 })); //return 0; //freopen("F:\\rush.txt", "r", stdin); pre(); in(); moni(); o(); //printf("\n%.2lf sec \n", (double)clock() / CLOCKS_PER_SEC); return 0; }
相关文章推荐
- [BZOJ 1033][ZJOI2008]杀蚂蚁antbuster
- [BZOJ 1033] [ZJOI2008] 杀蚂蚁antbuster 【模拟!】
- 【BZOJ1033】[ZJOI2008]杀蚂蚁antbuster【模拟】
- BZOJ 1033 [ZJOI2008]杀蚂蚁antbuster 模拟
- bzoj1033: [ZJOI2008]杀蚂蚁antbuster
- bzoj1033 [ZJOI2008]杀蚂蚁antbuster
- 【BZOJ1033】[ZJOI2008]杀蚂蚁antbuster【模拟】
- bzoj千题计划121:bzoj1033: [ZJOI2008]杀蚂蚁antbuster
- BZOJ 1033: [ZJOI2008]杀蚂蚁antbuster
- 【BZOJ 1033】 [ZJOI2008]杀蚂蚁antbuster
- [BZOJ1033][ZJOI2008]杀蚂蚁antbuster(大模拟)
- 【BZOJ 1033】 [ZJOI2008]杀蚂蚁antbuster
- bzoj1033: [ZJOI2008]杀蚂蚁antbuster
- 【BZOJ1033】[ZJOI2008]杀蚂蚁antbuster
- BZOJ 1033: [ZJOI2008]杀蚂蚁antbuster(模拟)
- 【BZOJ 1043】【HNOI 2008】下落的圆盘 判断圆相交+线段覆盖
- [bzoj1033] [ZJOI2008]杀蚂蚁 Big MoNI
- bzoj 1033【ZJOI2008】杀蚂蚁
- 判断两条线段是否相交
- 判断两条线段是否相交