Escape (可待在原地的bfs)

The students of the HEU are maneuvering for their military training. 
The red army and the blue army are at war today. The blue army finds that Little A is the spy of the red army, so Little A has to escape from the headquarters of the blue army to that of the red army. The battle field is a rectangle of size m*n, and the headquarters of the blue army and the red army are placed at (0, 0) and (m, n), respectively, which means that Little A will go from (0, 0) to (m, n). The picture below denotes the shape of the battle field and the notation of directions that we will use later. 



The blue army is eager to revenge, so it tries its best to kill Little A during his escape. The blue army places many castles, which will shoot to a fixed direction periodically. It costs Little A one unit of energy per second, whether he moves or not. If he uses up all his energy or gets shot at sometime, then he fails. Little A can move north, south, east or west, one unit per second. Note he may stay at times in order not to be shot. 
To simplify the problem, let’s assume that Little A cannot stop in the middle of a second. He will neither get shot nor block the bullet during his move, which means that a bullet can only kill Little A at positions with integer coordinates. Consider the example below. The bullet moves from (0, 3) to (0, 0) at the speed of 3 units per second, and Little A moves from (0, 0) to (0, 1) at the speed of 1 unit per second. Then Little A is not killed. But if the bullet moves 2 units per second in the above example, Little A will be killed at (0, 1). 
Now, please tell Little A whether he can escape. 

Input

For every test case, the first line has four integers, m, n, k and d (2<=m, n<=100, 0<=k<=100, m+ n<=d<=1000). m and n are the size of the battle ground, k is the number of castles and d is the units of energy Little A initially has. The next k lines describe the castles each. Each line contains a character c and four integers, t, v, x and y. Here c is ‘N’, ‘S’, ‘E’ or ‘W’ giving the direction to which the castle shoots, t is the period, v is the velocity of the bullets shot (i.e. units passed per second), and (x, y) is the location of the castle. Here we suppose that if a castle is shot by other castles, it will block others’ shots but will NOT be destroyed. And two bullets will pass each other without affecting their directions and velocities. 
All castles begin to shoot when Little A starts to escape. 
Proceed to the end of file. 

Output

If Little A can escape, print the minimum time required in seconds on a single line. Otherwise print “Bad luck!” without quotes.

Sample Input

4 4 3 10
N 1 1 1 1
W 1 1 3 2
W 2 1 2 4
4 4 3 10
N 1 1 1 1
W 1 1 3 2
W 1 1 2 4

Sample Output

9
Bad luck!

题意:红军战士从(0,0)点想要在 d 时间内回到(n,m)点,蓝军为了追杀他,在图上放了k个碉堡,每个碉堡只能朝给定的方向以周期为t,速度为v的固定模式射击。战士碰到子弹时,战士死亡,且战士只能在整数点上碰到子弹,子弹撞上碉堡后子弹会消失。刚开始时所有碉堡都开始射击。

思路:我们可以开一个三维数组num[i][j][k]来存碉堡的位置(i,j),周期num[i][j][0],以及速度num[i][j][1],以及射击方向num[i][j][2]。战士为了躲避子弹,每个点最多可以有5种走向,上下左右以及呆在原地。并且走下一个点时就需要判断是否会被杀死(四个方向),如果不会则将这个点入队列。并且用三维数组book来标记在这个点走过的步数,以后有相同的步数就不用入队列了。切记数据量大,book要用布尔型的。否则会爆内存。

代码如下:

#include<cstdio>
#include<cstring>
#include<queue>
#define inf 0x3f3f3f3f
using namespace std;  //num记录碉堡的状态
int n,m,tt,num[105][105][3],dir[5][2]={0,1,1,0,0,-1,-1,0,0,0};//五种走法
bool book[105][105][1005];//标记
struct node
{
    int x,y,n;
};
void bfs()
{
    memset(book,0,sizeof(book));
    queue<node>Q;
    node q,p;
    q.x=0;
    q.y=0;
    q.n=0;
    book[0][0][0]=1;
    Q.push(q); //起点入队列
    while(!Q.empty())  //非空
    {
        //printf("%d %d %d\n",n,m,tt);
        p=Q.front();
        Q.pop();
        if(p.n>tt)     //已经超时了,饿死了
        {
            printf("Bad luck!\n");
            return;
        }
        if(p.x==n&&p.y==m)  //走到了
        {
            printf("%d\n",p.n);
            return;
        }
        for(int i=0;i<5;i++)
        {

            q.x=p.x+dir[i][0];
            q.y=p.y+dir[i][1];
            q.n=p.n+1;          //不在图中,已经走过,这点有碉堡,时间已经超过了限制,直接跳过
            if(q.x<0||q.y<0||q.x>n||q.y>m||book[q.x][q.y][q.n]||q.n>tt||num[q.x][q.y][0])
                continue;
            int flag=1;  
            for(int j=q.x-1;j>=0;j--)  //判断上面是否安全
            {
                if(num[j][q.y][0]&&num[j][q.y][2]==3)  //上面有个碉堡的射击方向朝下,可能有危险
                {
                    int dis=q.x-j;      //战士距碉堡的距离
                    if(dis%num[j][q.y][1])    //不能整除速度的话,说明子弹不在这停留,战士是安全的,可以判断其他方向了
                        break;
                    int team=q.n-dis/num[j][q.y][1];   //战士已经走过的时间减去子弹第一次到达这里所需要的时间
                    if(team<0)      //说明此时子弹还没到过这里,暂时安全,可以停留
                        break;
                    if(team%num[j][q.y][0]==0)   //已经到达过这里,就要判断下一秒子弹是否会到达这里
                    {
                        flag=0;   //到达,被杀死了
                        break;
                    }
                }
                if(num[j][q.y][0]) //遇见任何一个碉堡就可以停了,因为碉堡挡子弹啊
                    break;
            }
            if(!flag)  //已经被杀死
                continue;

            for(int j=q.x+1;j<=n;j++)   //向下走的状态,不在赘述了
            {
                if(num[j][q.y][0]&&num[j][q.y][2]==1)
                {
                    int dis=j-q.x;
                    if(dis%num[j][q.y][1])
                        break;
                    int team=q.n-dis/num[j][q.y][1];
                    if(team<0)
                        break;
                    if(team%num[j][q.y][0]==0)
                    {
                        flag=0;
                        break;
                    }
                }
                if(num[j][q.y][0])
                    break;
            }
            if(!flag)
                continue;

            for(int j=q.y-1;j>=0;j--)  //向左走的状态,不在赘述了
            {
                if(num[q.x][j][0]&&num[q.x][j][2]==2)
                {
                    int dis=q.y-j;
                    if(dis%num[q.x][j][1])
                        break;
                    int team=q.n-dis/num[q.x][j][1];
                    if(team<0)
                        break;
                    if(team%num[q.x][j][0]==0)
                    {
                        flag=0;
                        break;
                    }
                }
                if(num[q.x][j][0])
                    break;
            }
            if(!flag)
                continue;

            for(int j=q.y+1;j<=m;j++)  //向右走的状态,不在赘述了
            {
                if(num[q.x][j][0]&&num[q.x][j][2]==4)
                {
                    int dis=j-q.y;
                    if(dis%num[q.x][j][1])
                        break;
                    int team=q.n-dis/num[q.x][j][1];
                    if(team<0)
                        break;
                    if(team%num[q.x][j][0]==0)
                    {
                        flag=0;
                        break;
                    }
                }
                if(num[q.x][j][0])
                    break;
            }
            if(!flag)
                continue;
                
            book[q.x][q.y][q.n]=1; //四个方向都判断完了且安全,就将这个状态标记,并入队列
            Q.push(q);
        }
    }
    printf("Bad luck!\n");//走不到
}
int main()
{
    int i,j,k,v,u,x,y;
    char str[10];
    while(~scanf("%d%d%d%d",&n,&m,&k,&tt))  
    {
        memset(num,0,sizeof(num));
        for(i=0;i<k;i++)
        {
            scanf("%s",str);
            scanf("%d%d%d%d",&u,&v,&x,&y);
            num[x][y][0]=u;
            num[x][y][1]=v;
            int a;
            if(str[0]=='N')
                a=1;
            else if(str[0]=='E')
                a=2;
            else if(str[0]=='S')
                a=3;
            else
                a=4;
            num[x][y][2]=a;
        }
        bfs();
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值