HDU - 1429 胜利大逃亡(续)(状态压缩+bfs)

中文题目不再对题意进行说明;

    之前一直懒不想写这道题,结果今天的测验里居然就出了跟这个一样的HDU-1885(见下面),嘤嘤嘤,真的不能偷懒……

题目思路题目戳我戳我

    这道题跟一般的bfs模板题唯一的区别就是不仅仅是“可通”或者“不可通”的状态,多了一些“门”,拿到钥匙就是可通的。所以我们就多了一个判断条件,就是遇到门并且此时有钥匙这一步才能加入队列(另外的条件比如不能越过迷宫边界、未访问过就不列举了,会在代码中体现);

    下面就是怎么在代码中体现出钥匙和门的关系,考虑遇到门时只有两种可能:有钥匙、没钥匙,而且只有从‘A’到‘J’11种可能的钥匙种类,那么我们可以考虑用二进制位数来保存是否有某个门的钥匙,比如A门有钥匙,那么二进制第一位就为1,没有钥匙就为0.而'j'-'a'=9,1<<9=512并不大,我们可以把vis数组开到三维,保存下此时的状态:位置x,位置y,有多少钥匙。那么根据我们前面分析的,当我们遇见了一个门的钥匙,要把相应位置变成1,这时我们可以想到位运算,比如:找到了c的钥匙,就可以用左移运算符(1<<3)和位或运算符(|),这样就可以把相应位置变为1;同样的,如果我们遇见了一个门,想要知道我们是否有这个门的钥匙,可以用位与运算符(&)来判断。

  这样之后,就跟普通的bfs没有任何区别了,加上我们的判断钥匙的那一步就可以了;

题目代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define maxn 30

using namespace std;
int dx[4]={1,0,-1,0};
int dy[4]={0,-1,0,1};
struct COO
{
     int x,y;
     int num,key;
}start,mid,nxt;
queue<COO>q;

char c[maxn][maxn];
bool vis[maxn][maxn][2000];
int sx,sy;
int n,m,t;

int bfs()
{
     start.x=sx;start.y=sy;
     start.num=start.key=0;
     vis[sx][sy][0]=true;
     q.push(start);
     while(!q.empty())
     {
          mid=q.front();
          q.pop();
          for(int i=0;i<4;i++)
          {
               //printf("%d-->\n",k);
               int nx=mid.x+dx[i];
               int ny=mid.y+dy[i];
               int k=mid.key;
               if(nx>=0&&nx<n&&ny>=0&&ny<m&&!vis[nx][ny][k])
               {
                    if(c[nx][ny]=='.')
                    {
                         nxt.x=nx;nxt.y=ny;
                         nxt.num=mid.num+1;
                         nxt.key=k;
                         if(nxt.num>=t)
                              return -1;
                         if(c[nx][ny]=='^')
                              return nxt.num;
                         q.push(nxt);
                         vis[nx][ny][k]=true;
                    }
                    else if(c[nx][ny]>='A'&&c[nx][ny]<='J')
                    {
                         if(k&(1<<(c[nx][ny]-'A')))//如果有这个钥匙
                         {
                              nxt.x=nx;nxt.y=ny;
                              nxt.num=mid.num+1;
                              nxt.key=k;
                              if(nxt.num>=t)//如果时间已经超过直接退出
                                   return -1;
                              if(c[nx][ny]=='^')//到达终点返回步数
                                   return nxt.num;
                              q.push(nxt);
                              vis[nx][ny][k]=true;
                         }
                    }
                    else if(c[nx][ny]>='a'&&c[nx][ny]<='j')
                    {
                         k|=(1<<c[nx][ny]-'a');//通过或运算添加钥匙
                         //printf("%d-->\n",1<<c[nx][ny]-'a');
                         if(!vis[nx][ny][k])//状态发生改变需要重新判断
                         {
                              nxt.x=nx;nxt.y=ny;
                              nxt.num=mid.num+1;
                              nxt.key=k;
                              if(nxt.num>=t)
                                   return -1;
                              if(c[nx][ny]=='^')
                                   return nxt.num;
                              q.push(nxt);
                              vis[nx][ny][k]=true;
                         }
                    }
                    else if(c[nx][ny]=='@'||c[nx][ny]=='^')
                    {
                         nxt.x=nx;nxt.y=ny;
                         nxt.num=mid.num+1;
                         nxt.key=k;
                         if(nxt.num>=t)
                              return -1;
                         if(c[nx][ny]=='^')
                              return nxt.num;
                         q.push(nxt);
                         vis[nx][ny][k]=true;
                    }
               }
          }
     }
     return -1;
}
int main(void)
{

     while(~scanf("%d%d%d",&n,&m,&t))
     {
          memset(vis,false,sizeof(vis));
          while(!q.empty())
               q.pop();
          for(int i=0;i<n;i++)
          {
               scanf("%s",c[i]);
          }
          for(int i=0;i<n;i++)
               for(int j=0;j<m;j++)
                    if(c[i][j]=='@')
                    {
                         sx=i;
                         sy=j;
                    }
          //
          int ans=bfs();
          printf("%d\n",ans);
     }
     return 0;
}

二、 HDU-1885

      跟上面的题几乎一样,但是不同的是此时的钥匙的字母的变化,之前最多是J,和A仅相差9,但是这道题最大的是Y,与A相差太多,如果我们同样开数组的话就会超内存 ,但比较好的情况是这道题只有4个门,我们可以不以他们与A的差值作为左移的位数,可以手动改变,反而可以更好地减小内存的使用;具体见代码里的说明。

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#define maxn 101

using namespace std;
int dx[4]={1,0,-1,0};
int dy[4]={0,-1,0,1};
struct COO
{
     int x,y,len;
     int yao;
}start,mid,nxt;
int up(char ch)//大写字母我们可以手动规定哪个字母移动几个位置,只要不重叠就可以
{
     switch(ch)
     {
          case 'B':return 1<<0;
          case 'Y':return 1<<1;
          case 'R':return 1<<2;
          case 'G':return 1<<3;
     }
}
int down(char ch)//小写字母和大写字母移动的位数照应
{
     switch(ch)
     {
          case 'b':return 1<<0;
          case 'y':return 1<<1;
          case 'r':return 1<<2;
          case 'g':return 1<<3;
     }
}
queue<COO>q;
int sx,sy;
bool vis[maxn][maxn][16];
int n,m;
char c[maxn][maxn];

int bfs()
{
     start.x=sx;start.y=sy;
     start.len=start.yao=0;
     vis[sx][sy][0]=true;
     q.push(start);
     while(!q.empty())
     {
          //printf("mm\n");
          mid=q.front();
          q.pop();

          for(int i=0;i<4;i++)
          {
               int nx=mid.x+dx[i];
               int ny=mid.y+dy[i];
               //printf("%d %d->%c\n",nx,ny,c[nx][ny]);
               int yao=mid.yao;
               if(nx<0||ny<0||nx>=n||ny>=m)
                    continue;
               if(!vis[nx][ny][yao])
               {
                    //printf("%d---->\n",yao);
                    if(c[nx][ny]=='.')
                    {
                         nxt.x=nx;nxt.y=ny;
                         nxt.yao=yao;nxt.len=mid.len+1;
                         if(c[nxt.x][nxt.y]=='X')
                         {
                              return nxt.len;
                         }
                         q.push(nxt);
                         vis[nx][ny][yao]=true;
                    }
                    else if((c[nx][ny]=='B'||c[nx][ny]=='Y'||c[nx][ny]=='R'||c[nx][ny]=='G')&&(yao&up(c[nx][ny])))
                    {
                         //cout<<yao<<"---"<<endl;
                         nxt.x=nx;nxt.y=ny;
                         nxt.yao=yao;nxt.len=mid.len+1;
                         if(c[nxt.x][nxt.y]=='X')
                         {
                              return nxt.len;
                         }
                         q.push(nxt);
                         vis[nx][ny][yao]=true;
                    }
                    else if(c[nx][ny]=='b'||c[nx][ny]=='y'||c[nx][ny]=='r'||c[nx][ny]=='g')
                    {
                         yao|=down(c[nx][ny]);
                         //printf("%d--\n",yao);
                         if(!vis[nx][ny][yao])
                         {
                              nxt.x=nx;nxt.y=ny;
                              nxt.yao=yao;nxt.len=mid.len+1;
                              if(c[nxt.x][nxt.y]=='X')
                              {
                                   return nxt.len;
                              }
                              q.push(nxt);
                              vis[nx][ny][yao]=true;
                         }
                    }
                    else if(c[nx][ny]=='*'||c[nx][ny]=='X')
                    {
                         nxt.x=nx;nxt.y=ny;
                         nxt.yao=yao;nxt.len=mid.len+1;
                         if(c[nxt.x][nxt.y]=='X')
                         {
                              return nxt.len;
                         }
                         q.push(nxt);
                         vis[nx][ny][yao]=true;
                    }
               }
          }
     }
     return -1;
}
int main(void)
{

     while(~scanf("%d%d",&n,&m)&&(n+m))
     {
          memset(vis,false,sizeof(vis));
          while(!q.empty())
               q.pop();
          for(int i=0;i<n;i++)
          {
               scanf("%s",c[i]);
          }
          for(int i=0;i<n;i++)
          {
               for(int j=0;j<m;j++)
               {
                    if(c[i][j]=='*')
                    {
                         sx=i;
                         sy=j;
                    }
               }
          }

          int ans=bfs();
          if(ans==-1)
               printf("The poor student is trapped!\n");
          else
               printf("Escape possible in %d steps.\n",ans);
          //printf("\n");
     }
}

呼呼~

猜你喜欢

转载自blog.csdn.net/destiny1507/article/details/81330518