poj 1924 The Treasure (bfs+地图预处理)

The Treasure
Time Limit: 5000MS Memory Limit: 30000K
Total Submissions: 2029 Accepted: 373

Description

We have arrived at the age of the Internet. Many software applications have transformed from stand-alone to online applications. Computer games are following this trend as well. Online games are becoming more and more popular, not only because they are more intelligent, but also because they can bring great profits. "The computer game industry is developing rapidly in China. Online game revenues amounted to 1.3 billion Yuan last year and are expected to reach 6.7 billion Yuan by 2007." reported by China Daily in 2004. 
However, good games originate from good programmers. We take for example that there is a RPG (Role Playing Game) and your boss asks you to implement some tasks. For simplicity’s sake, we assume there are two kinds of roles in this game: one is player and the other is monster. You should help the player to achieve the goal: reach the place where treasure is positioned as early as possible and get the treasure. 
The map of the game is a matrix of N * M identical cells. Some cells are passable blocks, and others are non-passable rocks. At any time, there is at most one role occupying a block. 
At the beginning, the time is set to 0, and the player is at a certain block. He then moves towards the treasure. At each turn, we have some rules: 
  • The player can stay in the same block during the next one-second time duration, or he can walk or run towards the east, south, west, north, northeast, northwest, southeast, and southwest. 
  • With walking, the player can arrive at the corresponding passable blocks around him (See Fig.1). Each move takes 1 second. 
  • With running, the player can arrive at the corresponding passable blocks 2 cells away from him (See Fig.2). Each run takes 1 second. As demonstrated in Fig.3, if a neighbor cell is not passable, the player cannot run in that direction. For example, if cell 2 is a rock, running from 1 to 3 is impossible. 
     
  • The monsters are classified into aggressive and non-aggressive. If a monster occupies a cell, the player cannot move into that cell or run through that cell. In addition, the player cannot move into the cells surrounding an aggressive monster, because it will attack the player near it. For example, in Fig.4, if there is an aggressive monster in 5, then the cell 1, 2, 3, 4, 6, 7, 8 and 9 are in its attacking region, so the player cannot stay in or pass through these cells. 
  • Monsters change their positions each turn. Each monster appears by its position sequence iteratively. That's to say, given the position sequence of monster i: (x1, y1), (x2, y2), ..., (xs, ys), its initial position is (x1, y1) at time 0, then it appears in (x2, y2) at time 1, and so on. When monster i arrives at (xs, ys) at time s-1, it will arrive in (x1, y1) at time s, and start to repeat. 
  • At the start of each turn, all the monsters change their positions first (the way of changing is given above). If a monster appears in the player's cell, or if an aggressive monster appears near the player to put him in its attacking region, the player will die, and the goal cannot be achieved. After all the monsters change their positions, the player makes a move or stays in the same cell. In his move, the moving path should not be occupied by any rocks or monsters or in the attacking region of any aggressive monsters. When counting the total time, we can neglect the time between monsters' position change and the player's move.

Given the map of the game, the player's starting position, the treasure position and all the monsters' positions in every second, your task is to write a program to find the minimum time that the player gets the treasure.

Input

The input consists of several test cases. The first line of each case contains two integers N and M (1 <= N, M <= 100), where N is the height of the map and M is the width of the map. This is followed by N lines each containing M characters representing the map. A '#' represents a rock, a '.' is a free block, 'p' is the starting position of the player, 't' is the position of the treasure, 'n' is the initial position of a non-aggressive monster, and an 'a' stands for the initial position of an aggressive monster. 
The cell (i, j) is the j-th cell on the i-th row counting from left to right. The rows are counted from 1 to N starting from the first line of the matrix. We can number all the monsters as 1, 2, 3… according to their initial position, sorting first by row, then by column. 
The (n+2)-th line contains an integer p (0 <= p <= 100), which is the total number of monsters (i.e. the total number of 'n's and 'a's in the matrix). It is followed by p lines each specifying a monster's position sequence in the following format: the i-th (1 <= i <= p) line corresponds to monster i, which begins with an integer s (1 <= s <= 100), meaning the length of position sequence. Then s pairs of integers x1, y1, x2, y2, …, xs, ys are followed, separated by blanks. Each pair is a free block in the map, (i.e. a monster never goes to a rock cell). 
It is assured that none of the aggressive monsters' initial position is around the player. Two consecutive cases are separated by a blank line. The input is terminated by a line containing a pair of zeros. 

Output

For each test case, output the minimum total time required for the player to get the treasure, in seconds. If it's not possible to get the treasure, or the minimum required time is greater than 100 seconds, please print a line just containing the string "impossible". Two consecutive cases should be separated by a blank line.

Sample Input

7 8
#.#####.
#.t#..p.
#..#....
..#a.#.#
#...##.n
.#......
........
2
2 4 4 5 4
3 5 8 6 8 5 7

3 3
p#.
##.
t..
0

2 2
#t
p#
0

0 0

Sample Output

8

impossible

1

Hint

In the first sample case, the player can follow (2,7), (4,7), stay in (4,7), (6,7), (7,6), (7,4), (5,2), (3,2) and (2,3) to get the treasure with the minimum time (8 seconds).

题意:在N*M的的地图中,有p个怪物,a表示可以攻击周围的怪物,n表示只能攻击当前位置的怪物。

给你每个怪物nge位置,然后每一秒移动到下一个位置,重复移动。

问你最少在100步以内能不能找到宝物。


思路:一般的bfs+地图预处理    (可将每一个时间地图的情况都预处理出来   则可将怪物及其攻击范围可看做墙)

然后就是要注意的是  每步都是怪物先走  怪物走完然后才是人走  有可能怪物走了之后就把人已经吃了 就不能完成了  


感想:做这题时状态不好  判断是否能走时想错了  坑了我很久。。。   这说明状态一定要好  效率才能高!


代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
#define maxn 105
using namespace std;

int n,m,ans,cnt;
int sx,sy,ex,ey;
char s[maxn];
int walkx[9]= {-1,1,0,0,-1,-1,1,1,0};  // walk stay
int walky[9]= {0,0,-1,1,-1,1,-1,1,0};
int runx[8]= {-2,2,0,0,-2,-2,2,2};     // run
int runy[8]= {0,0,-2,2,-2,2,-2,2};
bool mp[maxn][maxn][maxn];             // time x y
bool tmp[maxn][maxn];
bool vis[maxn][maxn][maxn];            // time x y    三维数组判重
bool type[maxn];
struct node
{
    int step;
    int xx,yy;
} cur,now;
queue<node>q;

bool isok(int x1,int y1,int tst,int dir,int flag)       // 判断是否能走
{
    int i,j,xx,yy,temp,xx1,yy1;
    if(x1<1||x1>n||y1<1||y1>m||vis[tst][x1][y1]||tst>100) return false ;            
    if(flag)                          // 如果是跑的话  还要注意不能穿过墙和怪物级攻击范围
    {
        x1-=walkx[dir];
        y1-=walky[dir];
        if(mp[tst][x1][y1]) return false ;
        x1+=walkx[dir];
        y1+=walky[dir];
        if(mp[tst][x1][y1]||mp[tst][x1-runx[dir]][y1-runy[dir]]) return false ;    // 开始就WA在这里判断是否能走了
    }
    else if(mp[tst][x1][y1]||mp[tst][x1-walkx[dir]][y1-walky[dir]]) return false ;
    return true ;
}
bool bfs()
{
    int i,j;
    int nx,ny,nstep,tx,ty,tstep;
    while(!q.empty()) q.pop();
    memset(vis,0,sizeof(vis));
    cur.xx=sx;
    cur.yy=sy;
    cur.step=0;
    q.push(cur);
    vis[0][sx][sy]=1;
    while(!q.empty())
    {
        now=q.front();
        nx=now.xx;
        ny=now.yy;
        nstep=now.step;
 //       printf("nx:%d ny:%d step:%d\n",nx,ny,nstep);
        if(nx==ex&&ny==ey)
        {
            ans=nstep;
            return true ;
        }
        for(i=0; i<9; i++)           // 走的8个方向及站着不动
        {
            tx=nx+walkx[i];
            ty=ny+walky[i];
            tstep=nstep+1;
            if(isok(tx,ty,tstep,i,0))
            {
                vis[tstep][tx][ty]=1;
                cur.xx=tx;
                cur.yy=ty;
                cur.step=tstep;
                q.push(cur);

            }
            if(i<8)                  // 跑的8个方向
            {
                tx=nx+runx[i];
                ty=ny+runy[i];
                tstep=nstep+1;
                if(isok(tx,ty,tstep,i,1))
                {
                    vis[tstep][tx][ty]=1;
                    cur.xx=tx;
                    cur.yy=ty;
                    cur.step=tstep;
                    q.push(cur);
                }
            }
        }
        q.pop();
    }
    return false ;
}
int main()
{
    int i,ii,j,jj,p,ss,k=0,monx,mony;
    while(scanf("%d%d",&n,&m),n||m)
    {
        memset(tmp,1,sizeof(tmp));       // 存原始地图
        cnt=0;
        for(i=1; i<=n; i++)
        {
            scanf("%s",s);
            for(j=1; j<=m; j++)
            {
                if(s[j-1]=='.')
                {
                    tmp[i][j]=0;
                }
                else if(s[j-1]=='p')
                {
                    tmp[i][j]=0;
                    sx=i;
                    sy=j;
                }
                else if(s[j-1]=='t')
                {
                    tmp[i][j]=0;
                    ex=i;
                    ey=j;
                }
                else if(s[j-1]=='a')
                {
                    tmp[i][j]=0;
                    cnt++;
                    type[cnt]=1;
                }
                else if(s[j-1]=='n')
                {
                    tmp[i][j]=0;
                    cnt++;
                    type[cnt]=0;
                }
            }
        }
        for(i=1; i<=100; i++)
        {
            memcpy(mp[i],tmp,sizeof(tmp));
        }
        scanf("%d",&p);
        for(i=1; i<=p; i++)          // 将每一个时间地图的情况都预处理出来   则可将怪物看做墙
        {
            scanf("%d",&ss);
            for(j=0; j<ss; j++)
            {
                scanf("%d%d",&monx,&mony);
                if(type[i])
                {
                    for(jj=j; jj<=102; jj+=ss)
                    {
                        for(ii=0; ii<9; ii++)
                        {
                            mp[jj][monx+walkx[ii]][mony+walky[ii]]=1;
                        }
                    }
                }
                else
                {
                    for(jj=j; jj<=102; jj+=ss)
                    {
                        mp[jj][monx][mony]=1;
                    }
                }
            }
        }
        k++;
        if(k!=1) printf("\n");
        if(bfs()) printf("%d\n",ans);
        else  printf("impossible\n");
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值