中文题目不再对题意进行说明;
之前一直懒不想写这道题,结果今天的测验里居然就出了跟这个一样的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");
}
}
呼呼~