BFS hdu-4528 小明系列故事——捉迷藏

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=4528

题目意思:

给你一个矩阵,'.‘ 表示能通过,’X' 表示不能通过,告诉你S、D、E 的位置。

问你从S出发在规定的时间内,能否同时找到D和E。只要两个人之间没有障碍,就能找到。

解题思路:

BFS,注意记录访问过的节点的时候,要注意状态的确定。

vis[x][y][i][j]是否访问坐标为x,y,且看到D和E的状态。i=0表示没看到D,i=1表示看到了D,j=0表示没看到E,j=1表示看到了E。

贴出一组测试数据:

7 7 19

S。。。。。。

。X。。。。。

。。X。。。。

。。。X。。。

。。。。X。。

。。。。。XD

。。。。。。E

答案为:18


代码:

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<stack>
#include<list>
#include<queue>
#define eps 1e-6
#define INF (1<<30)
#define PI acos(-1.0)
using namespace std;


char save[120][120];
bool se[2][120][120],vis[120][120][2][2];
struct Po
{
   int x,y,t;
   bool flag1,flag2;
}s,d,e;
int dir[4][2]={0,-1,1,0,0,1,-1,0};
int n,m,t;

bool check(int x,int y)
{
   if(x<1||x>n||y<1||y>m)
      return false;
   return true;
}

void init(int x,int y,int num)
{
   for(int i=0;i<4;i++)
   {
      int xx=x,yy=y;

      while(true)  //预处理能找到D和E的位置
      {
         xx+=dir[i][0],yy+=dir[i][1];
         if(check(xx,yy)==false||save[xx][yy]=='X')
            break;
         if(num==0&&save[xx][yy]=='E') //注意开始S的位置,应该把它当做.
            break;
         if(num==1&&save[xx][yy]=='D')
            break;
         se[num][xx][yy]=true;
      }
   }
   return ;
}

bool flag;

int bfs()
{
   queue<struct Po>myq;
   s.t=0;
   myq.push(s);

   while(!myq.empty())
   {
      struct Po cur=myq.front();
      myq.pop();

      for(int i=0;i<4;i++)
      {
         int xx=cur.x+dir[i][0],yy=cur.y+dir[i][1],tt=cur.t+1;

         if(tt>t)
            break;
         if(check(xx,yy)==false||save[xx][yy]!='.')
            continue;
         struct Po temp;
         if(se[0][xx][yy]||cur.flag1) //如果前面已找到了D,或者当前恰好找到了D
            temp.flag1=true;
         else
            temp.flag1=false;

         if(se[1][xx][yy]||cur.flag2)
            temp.flag2=true;
         else
            temp.flag2=false;

         if(temp.flag1&&temp.flag2)
         {
            flag=true;
            return tt;
         }
         if(vis[xx][yy][temp.flag1][temp.flag2]) //状态前面已经找了
            continue;

         temp.x=xx,temp.y=yy,temp.t=tt;
         vis[xx][yy][temp.flag1][temp.flag2]=true;
         myq.push(temp);
      }
   }
   return -1;
}

int main()
{
   int tt;

   scanf("%d",&tt);
   for(int ca=1;ca<=tt;ca++)
   {
      scanf("%d%d%d",&n,&m,&t);
      for(int i=1;i<=n;i++)
      {
         scanf("%s",save[i]+1);
         for(int j=1;j<=m;j++)
         {
            if(save[i][j]=='S')
               s.x=i,s.y=j;
            if(save[i][j]=='D')
               d.x=i,d.y=j;
            if(save[i][j]=='E')
               e.x=i,e.y=j;
         }
      }
     // printf("s:%d %d  e:%d %d  d:%d %d\n",s.x,s.y,e.x,e.y,d.x,d.y);
      memset(se,false,sizeof(se));
      init(d.x,d.y,0); //预处理能够看见的D的坐标
      init(e.x,e.y,1); //预处理能够看见的E的坐标

      flag=false;
      if(se[0][s.x][s.y])
         s.flag1=true;
      else
         s.flag1=false;
      if(se[1][s.x][s.y])
         s.flag2=true;
      else
         s.flag2=false;
      printf("Case %d:\n",ca);
      if(s.flag1&&s.flag2)
      {
         printf("0\n");
         continue;
      }
      memset(vis,false,sizeof(vis));
      vis[s.x][s.y][s.flag1][s.flag2]=true;
      int ans=bfs();
      if(flag==false)
         printf("-1\n");
      else
         printf("%d\n",ans);
   }

   return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值