hdu1728 很有难度的bfs…

题意:
给定一个m × n (m行,n列)的迷宫,迷宫中有两个位置,gloria想从迷宫的一个位置走到另外一个位置,当然迷宫中有些地方是空地,gloria可以穿越,有些地方是障碍,她必须绕行,从迷宫的一个位置,只能走到与它相邻的4个位置中,当然在行走过程中,gloria不能走到迷宫外面去。令人头痛的是,gloria是个没什么方向感的人,因此,她在行走过程中,不能转太多弯了,否则她会晕倒的。我们假定给定的两个位置都是空地,初始时,gloria所面向的方向未定,她可以选择4个方向的任何一个出发,而不算成一次转弯。gloria能从一个位置走到另外一个位置吗?

这题用普通的方法 不是超时 , 就是wa 。
老子我提交了50+
这题的数据确实是很牛逼啊 , 决对是设计出来的
到现在我还不知道我那个方法 , 为什么会wa

网上解题报告的解法:
这题用bfs来做 , 关键在于以一个什么方法来标记已经走过的点 , 这个地方 , 就是这个题目的关键 , 把这个问题解决了 ,这个题目也就A了

网上是这样做得 , 每次走的时候 , 都把这一方向的所以点走遍 , 然后把走过的点都标记 ,这样就能保证第一次走过这个点的时候的转弯次数一定是最少的。

代码:
#include
#include
#include
#include
using namespace std;

#define maxn 1100
char grap[maxn][maxn] ;
int  pre[maxn][maxn];
int n , m;
int d_x[4] = {-1 , 1, 0 , 0};
int d_y[4] = {0 , 0 , -1 , 1};
int g , h , k ;
int sum , cf;

typedef struct xyy
{
      int x ,y;
      intsum;
      int f;
}edge;

void init()
{
      int i ,j;
      memset(pre ,0 , sizeof(pre));
      for(i = 0; i<= m+1 ; i++)
            grap[0][i] =grap[n+1][i] = '*';
      for(i = 0; i<= n+1 ; i++)
            grap[i][0] =grap[i][m+1] = '*';
      sum =0;
      cf =-1;
}

void bfs(int x , int y)
{
      queueq;
      edge xy;
      xy.x = x ,xy.y = y , xy.sum = 0 , xy.f = -1;
      q.push(xy);
      pre[x][y] =1;
      int i;
      while(!q.empty())
      {
              edge gh = q.front() , cf;
            q.pop();
              int x , y;
             
              for(i = 0; i < 4; i++)
              {
                  x =gh.x+d_x[i];
                      y = gh.y+d_y[i];
                 
                  cf.sum =gh.sum;
                  cf.f =i;
                  if(gh.f !=-1 && gh.f != i)
                  {
                        cf.sum =gh.sum + 1;
                  }
                 
                  if(cf.sum> k)  continue ;
                  while(grap[x][y] != '*')
                  {
                        if(pre[x][y]== 0)
                        {
                              cf.x =x;
                              cf.y =y;
                              if(cf.x == g&& cf.y == h && cf.sum <= k)
                              {
                                    printf("yes\n");
                                    return;
                              }
                              q.push(cf);
                              pre[x][y] =1;
                        }
                        x +=d_x[i];
                        y +=d_y[i];
                  }
            }
      }
      printf("no\n");
}


int main()
{
      int t;
      scanf("%d" ,&t);
      while(t--)
      {
             
              scanf("%d %d" , &n , &m);
              init();
            charch;
              int i , x , y , j;
              for( i=1;i<=n;i++)
              {
                      getchar();
                      for( j=1;j<=m;j++)
                      {
                              scanf("%c",&ch);
                              grap[i][j]=ch;
                      }
                      //getchar();
              }
              scanf("%d %d %d %d %d" , &k , &y , &x , &h ,&g);

            if(x==g&& y==h) printf("yes\n");
              else bfs(x , y);
           
     
         
      }
      return0;
}

下面是我自己的方法 , 一直wa , 一直不知道是哪错了

定义了一个数组pre , 来标记到达每个点的最小转弯次数 , 同时判断这个点能不能入队列(能不能继续往下走) ,只有这点的转弯次数会小于等于 , 当前这个点的最小转弯次数时 , 才能入队列
pre[xx][yy] < cf.sum

这里有一个bug , 假如当前这个点的最小转弯次数为x , 而现在你有到达这个点 , 且这个点的转弯次数也是x , 此时 ,这个点也要入队列 , 因为从这个点到目标点 , 可能还要再转弯一次 。

代码:
#include
#include
#include
#include
using namespace std;

#define maxn 1100
char grap[maxn][maxn] ;
int  pre[maxn][maxn];
int n , m;
int d_x[4] = {-1 , 1, 0 , 0};
int d_y[4] = {0 , 0 , -1 , 1};
int g , h , k ;

typedef struct xyy
{
      int x ,y;
      intsum;
      int f;
}edge;

void init()
{
//      memset(pre, 0 , sizeof(pre));
      int i ,j;
      for(i = 0; i<= m+1 ; i++)
            grap[0][i] =grap[n+1][i] = '*';
      for(i = 0; i<= n+1 ; i++)
            grap[i][0] =grap[i][m+1] = '*';
      for(i = 1; i<= n; i++)
            for(j = 1; j<= m; j++)
                  pre[i][j] =120;
}

void bfs(int x , int y)
{
      queueq;
      edge xy ,cf;
      xy.x = x ,xy.y = y , xy.sum = 0 , xy.f = -1;
      q.push(xy);
      pre[x][y] =0;
      int i , xx ,yy;
      while(!q.empty())
      {
            edge gh =q.front() ;
            q.pop();
      //      if(gh.sum> k)  continue ;
     
            for(i = 0; i< 4; i++)
            {
                  xx =gh.x+d_x[i];
                  yy =gh.y+d_y[i];
                  if(grap[xx][yy]=='.')
                  {
                        cf.x =xx;
                        cf.y =yy;
                        cf.sum =gh.sum;
                        cf.f =i;
                        if(gh.f !=-1 && gh.f != i)  cf.sum = gh.sum +1;
                       
                        if(cf.sum> k || pre[xx][yy] < cf.sum)  continue;

                        if(xx == g&& yy == h && cf.sum <= k)
                        {
                              printf("yes\n");
                              return;
                        }
                        q.push(cf);
                        pre[xx][yy]= cf.sum;
                       
                  }
            }
      }
      printf("no\n");
}


int main()
{
      int t;
      scanf("%d" ,&t);
      while(t--)
      {
           
            scanf("%d%d" , &m , &n);
            init();
            int i , x ,y , j;
            charch;
            for(i=1;i<=n;i++)
              {
                      getchar();
                      for( j=1;j<=m;j++)
                      {
                              scanf("%c",&ch);
                              grap[i][j]=ch;
                      }
                      //getchar();
              }
            scanf("%d %d%d %d %d" , &k , &y , &x , &h , &g);
            if(x == g&& y == h)
                  printf("yes\n");
            else bfs(x ,y);

      }
      return0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值