题意:改编了保卫萝卜的部分功能,给你4个塔和怪物什么的,来模拟是否能够消灭怪物。
解法:比赛的时候一直在敲这题,但是一直wa,结果赛后发现是有数组开小了。。。真是渣渣。。。
由于要考虑怪物的路径,所以用BFS先找出了路径。
之后就是模拟。
总结:太不细心,代码手速太慢。
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
struct node
{
int x,y;
int step;
} tower[5][300]; //记录4塔的位置,0-3分别表示三种塔
int pat[20][20],pplen[20][20];
//用来记录路径,pplen记录当前位置到终点的步数,判断攻击的目标时要用。
//pat用来记录路径,当前点的下一个运动方向
int tsum[5],plen; //tsum 记录相应塔的数量
char map[20][20];
struct monster
{
int x,y,born,hp;
bool need,ice;
} mon[60];
//怪物信息,分别表示坐标,born出生的时间,小于0表示还没出生,大于0的才可以动什么的。
//hp血量,need,ice表示是否中毒或者冻住
int m,n,k,h;
int sx,sy,ex,ey,down; //怪物的起始节点和萝卜的节点
int vis[30][30];
int downhp[60];
bool downice[60];
//由于塔是同时攻击的,所以用这两个数组来记录某次攻击,某个怪物是否要扣血和冻住
//刚开始就由于没看到这个,然后是一个个炮塔去处理,结果wa到死
//最后加了这个之后还是wa,但是数组开小了,赛后才发现,跪。
int pan(char ch) //判断塔的类型
{
if(ch=='B') return 0;
if(ch=='F') return 1;
if(ch=='N') return 2;
if(ch=='I') return 3;
return -1;
}
int dir[4][2]= {{1,0},{-1,0},{0,1},{0,-1}};
int dir1[8][2]= {{1,0},{-1,0},{0,1},{0,-1},{1,1},{1,-1},{-1,1},{-1,-1}};
bool inMap(int x,int y)
{
return (x>=0&&x<m&&y>=0&&y<n);
}
void BFS()
{
int i,j,x,y,d;
node temp,newtemp;
queue<node>q;
memset(vis,-1,sizeof(vis));
temp.x=sx,temp.y=sy,temp.step=0;
vis[sx][sy]=-2;
q.push(temp);
while(!q.empty())
{
temp=q.front();
q.pop();
if(temp.x==ex&&temp.y==ey)
{
plen=temp.step;
x=ex,y=ey;
while(x!=sx||y!=sy)
{
d=vis[x][y];
pplen[x][y]=temp.step-plen;
x-=dir[d][0];
y-=dir[d][1];
pat[x][y]=d;
plen--;
}
pplen[sx][sy]=temp.step;
return ;
}
for(i=0; i<4; i++)
{
newtemp=temp;
newtemp.x+=dir[i][0];
newtemp.y+=dir[i][1];
newtemp.step++;
if(inMap(newtemp.x,newtemp.y)&&vis[newtemp.x][newtemp.y]==-1
&&(map[newtemp.x][newtemp.y]=='.'||map[newtemp.x][newtemp.y]=='T'))
{
vis[newtemp.x][newtemp.y]=i;
q.push(newtemp);
}
}
}
}
int nearest(int x,int y) //根据题意找攻击对象
{
int i,j,a,b,mm=-1;
for(i=0;i<8;i++)
{
a=x+dir1[i][0];
b=y+dir1[i][1];
if(inMap(a,b))
{
for(j=0;j<k;j++)
{
if(mon[j].x==a&&mon[j].y==b&&mon[j].hp>0&&mon[j].born>=0)
{
if(mm==-1) mm=j;
else
{
if(pplen[mon[mm].x][mon[mm].y]>pplen[a][b])
mm=j;
else if(pplen[mon[mm].x][mon[mm].y]==pplen[a][b])
{
if(mon[mm].born<mon[j].born)
mm=j;
}
}
}
}
}
}
return mm;
}
void attack0() //B
{
int i,j,a,b,x,y,d;
for(i=0;i<tsum[0];i++)
{
x=tower[0][i].x;
y=tower[0][i].y;
d=nearest(x,y);
if(d!=-1)
{
downhp[d]+=10;
down++;
}
}
}
void attack1() //F
{
int i,j,a,b,tt,x,y;
for(i=0;i<tsum[1];i++)
{
x=tower[1][i].x;
y=tower[1][i].y;
for(j=0;j<8;j++)
{
a=x+dir1[j][0];
b=y+dir1[j][1];
if(inMap(a,b))
{
for(tt=0;tt<k;tt++)
{
if(mon[tt].x==a&&mon[tt].y==b&&mon[tt].born>=0&&mon[tt].hp>0)
{
downhp[tt]+=10;
down++;
}
}
}
}
}
}
void attack2() //N
{
int i,j,a,b,x,y,d;
for(i=0;i<tsum[2];i++)
{
x=tower[2][i].x;
y=tower[2][i].y;
d=nearest(x,y);
if(d!=-1)
mon[d].need=1;
}
}
void attack3() //I
{
int i,j,a,b,x,y,d;
for(i=0;i<tsum[3];i++)
{
x=tower[3][i].x;
y=tower[3][i].y;
d=nearest(x,y);
if(d!=-1)
downice[d]=1;
}
}
int main()
{
int T,i,j,x,minter;
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d%d",&m,&n,&k,&h);
for(i=0; i<m; i++) scanf("%s",map[i]);
memset(tsum,0,sizeof(tsum));
for(i=0; i<m; i++)
for(j=0; j<n; j++)
{
if(map[i][j]=='S')
{
sx=i;
sy=j;
}
if(map[i][j]=='T')
{
ex=i;
ey=j;
}
x=pan(map[i][j]);
if(x>=0)
{
tower[x][tsum[x]].x=i,tower[x][tsum[x]].y=j;
tsum[x]++;
}
}
BFS();
for(i=0; i<k; i++)
{
mon[i].x=sx,mon[i].y=sy;
mon[i].hp=h;
mon[i].born=-1*i-1;
//born初始状态为-1到-k-1,大于0的才可以进行操作
//这样在每一秒的时候,先对born大于0的进行操作之后再给每个born++
//就解决了第一秒不能动但是能被攻击的情况
mon[i].ice=mon[i].need=0;
}
bool die=false;
for(minter=1;; minter++)
{
memset(downhp,0,sizeof(downhp));
memset(downice,0,sizeof(downice));
down=0;
for(i=0; i<k; i++)
{
if(mon[i].need&&mon[i].hp>0) { mon[i].hp-=10; down++; }
if(mon[i].born>=0&&mon[i].hp>0)
{
if(mon[i].ice==0)
{
int xx;
xx=pat[mon[i].x][mon[i].y];
mon[i].x+=dir[xx][0];
mon[i].y+=dir[xx][1];
if(mon[i].x==ex&&mon[i].y==ey)
{
die=1; break;
}
}
else mon[i].ice=0;
}
mon[i].born++;
}
if(die) break;
attack0();
attack1();
attack2();
attack3();
for(i=0;i<k;i++)
{
if(downhp[i]) mon[i].hp-=downhp[i];
if(downice[i]) mon[i].ice=1;
}
int ksum=0;
for(i=0;i<k;i++)
if(mon[i].hp<=0) ksum++;
if(ksum==k) break;
if(down==0&&minter>100) break;
//判断当所有怪都是被冻住的状态,但是没有能扣血,这样也是不能消灭怪物的,要跳出
//定义了一个最大的移动步数,本来是2500的,但后来发现减到100也能过,但求证明想法
}
if(down==0&&minter>100) printf("-1\n");
else if(!die) printf("%d\n",minter);
else printf("-1\n");
}
return 0;
}