啊,大模拟~
搜集了几位神犇总结的坑点1,加上我自己发现的一些:
vector
+erase()
,也很方便。直接用构造函数和析构函数实现蚂蚁的出生和死亡,在vector
中存指针,可以保证不出现重复的对象或意外产生复制构造或析构的情况。erase
掉死蚂蚁就好。int
而避免使用double
的做法: int
直接存下。整数比较就不存在精度问题了。 然后就自己码大模拟吧。WA了就把题从头到尾再仔细读一遍,看是否哪里理解错了。
#include
#include
#include
using namespace std;
//basic operations with positions & vectors
struct Vector {
int x, y;
inline bool legal() const;
template <typename Tp>
inline Tp& operator [] (Tp array[10][10]) const {return array[x][y];} //call map[x][y] by pos[map]
inline Vector operator + (const Vector &v) const {return (Vector){x+v.x, y+v.y};}
inline Vector operator - (const Vector &v) const {return (Vector){x-v.x, y-v.y};}
inline bool operator == (const Vector &v) const {return x == v.x && y == v.y;}
inline bool operator != (const Vector &v) const {return x != v.x || y != v.y;}
inline int operator * (const Vector &v) const {return x*v.x + y*v.y;}
inline int operator ^ (const Vector &v) const {return x*v.y - y*v.x;}
inline void operator += (const Vector &v) {x += v.x; y += v.y; }
inline int len() const {return x * x + y * y;} //return len^2
inline bool online(const Vector &p, const Vector &q) const { //dis to line(p,q) <= 0.5
Vector v = q - p, u = operator-(p);
int l1 = u ^ v, l2 = u * v, lv = v.len(); //avoid using double
return 4*l1*l1 <= lv && l2 >= 0 && l2 <= lv;
}
};
const Vector dir[] = {{0,1},{1,0},{0,-1},{-1,0}}; //4 dirs in clockwise order
struct Ant {
Vector pos, last;
int age, level, health, healthMax;
//Needn't to remember if carrying cake. Check (cake == this) instead
inline Ant(); //born
inline void leavePhero();
void movePos();
void takeCake();
inline ~Ant(); //die
};
struct Laser {
Vector pos;
void shoot();
};
//GROUND
int N, M;
bool ocpy[10][10]; //occupied by ant or laser
int phero[10][10]; //pheromone
inline bool Vector::legal() const { //within ground && not occupied
return x>=0 && x<=N && y>=0 && y<=M && !ocpy[x][y];
}
void losePhero() { //phero-- if exist
for (int x = 0; x <= N; x++)
for (int y = 0; y <= M; y++)
if (phero[x][y]) phero[x][y]--;
}
//ANT
vector ants; //living ants
int totAnt = 0; //tot ants ever existed
Ant *cake = NULL; //point to ant who carries cake
typedef vector ::iterator It; //loops are more convenient with C++11
//born at home //NOTICE age=0 not same as description
inline Ant::Ant(): age(0), level(totAnt++ / 6 + 1) {
pos.x = pos.y = 0;
pos[ocpy] = true;
last = pos;
health = healthMax = 4 * pow(1.1, level);
}
//leave pheromone on ground
inline void Ant::leavePhero() { pos[phero] += cake == this ? 5 : 2; }
//Choose a direction & Move its way
void Ant::movePos() {
static int freeDir[4]; //accessible directions
int cnt = 0, best, val = -1;
for (int i = 0; i < 4; i++) { //++i to turn clockwise
Vector nx = pos + dir[i];
if (nx.legal() && nx != last) {
if (nx[phero] > val) {
val = nx[phero];
best = cnt;
}
freeDir[cnt++] = i;
}
}
last = pos;
if (!cnt) return; //no way accessible
if (age % 5 == 4) //NOTICE not same as description
if (best) best--; //--i to turn counterclockwise
else best = cnt - 1;
pos[ocpy] = false;
pos += dir[freeDir[best]];
pos[ocpy] = true;
}
//try to carry cake. Assume cake is on ground
void Ant::takeCake() {
if (pos.x < N || pos.y < M) return; //must at cake's pos
cake = this; //become target of all lasers
if ((health += healthMax/2) > healthMax)
health = healthMax;
}
//die
inline Ant::~Ant() {
if (cake == this) cake = NULL; //set cake back to ground
pos[ocpy] = false;
}
//LASER
int totLaser;
Laser lasers[22];
int damage, range; //range = radius^2
//Aim & Shoot
void Laser::shoot() {
Vector tar; //target pos
if (cake && (cake->pos - pos).len() <= range)
tar = cake->pos; //aim at cake if possible
else {
int nearest = range + 1; //find nearest target
for (It i = ants.begin(); i != ants.end(); i++) {
int dis = ((*i)->pos - pos).len();
if (dis < nearest) {
nearest = dis;
tar = (*i)->pos;
}
}
if (nearest > range) return; //out of range
}
for (It i = ants.begin(); i != ants.end(); i++) //hurt every ant online
if ((*i)->pos.online(pos, tar)) (*i)->health -= damage;
}
//GENERAL MANAGING
int main() {
scanf("%d%d%d%d%d",&N,&M,&totLaser,&damage,&range);
range *= range; //range = radius^2
for (int i = 0; i < totLaser; i++) {
scanf("%d%d",&lasers[i].pos.x,&lasers[i].pos.y);
lasers[i].pos[ocpy] = true;
}
int t, T;
scanf("%d",&T);
bool gameOver = false;
for (t = 1; t <= T; t++) {
//born new ant if (ants less than 6 && home is free)
if (ants.size() < 6 && !ocpy[0][0]) ants.push_back(new Ant); //this calls Ant::Ant()
//leave pheromone & move & try to take cake
for (It i = ants.begin(); i != ants.end(); i++) {
(*i)->leavePhero();
(*i)->movePos();
if (!cake) (*i)->takeCake();
}
//lasers shoot. regardless if ant is alive
for (int i = 0; i < totLaser; i++)
lasers[i].shoot();
//clear out dead ants
for (It i = ants.begin(); i != ants.end(); )
if ((*i)->health < 0) {
delete *i; //this calls Ant::~Ant()
i = ants.erase(i);
}
else i++;
//GG if cake arrives home
if (cake && !cake->pos.x && !cake->pos.y) {
gameOver = true;
break;
}
//ground lose pheromone & ants get older
losePhero();
for (It i = ants.begin(); i != ants.end(); i++)
(*i)->age++;
}
if (gameOver) printf("Game over after %d seconds\n",t);
else puts("The game is going on");
printf("%llu\n",ants.size());
for (It i = ants.begin(); i != ants.end(); i++)
printf("%d %d %d %d %d\n",(*i)->age,(*i)->level,(*i)->health,(*i)->pos.x,(*i)->pos.y);
return 0;
}