链接:点击打开链接
思路:刚开始我想的是两个bfs,来找最少的时间,就是先找门,根据门在找钥匙。但是WA,果断是想简单啦。如果在找门的途中就可以找到钥匙,就不要返回去找啦,所以我的想法错啦。后面是看解题报告,要用二进制位运算来做,其实标记数组加一维来计算拾到的钥匙。发现好多题都是这个标记数组牛逼啦,太他妈神啦。。
用二进制来表示手头的钥匙有哪些,100表示有第三把钥匙,111表示有第三、二、一把,搜索下一点时,如果该点为钥匙点,则可采用|运算来模拟拾取,显然0001 | 1000 = 1001,同理,当为相应的门时采用&运算来模拟开启,例如1101 & 0001 = 0001(即可以打开'A'门)
#include<iostream>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;
struct node{
int x;
int y;
int time;
int nkey;
};
bool vis[30][30][1025];
int n,m,t,a[4][2]={{0, 1}, {0, -1}, {-1, 0}, {1, 0}};;
int map[30][30],fx,fy,ex,ey;
void bfs(){
int i,xx;
queue<node>Q;
node p,q;
p.x=fx;
p.y=fy;
p.time=0;
p.nkey=0;
vis[p.x][p.y][p.nkey]=1;
Q.push(p);
while(!Q.empty()){
p=Q.front();
Q.pop();
for(i=0;i<4;i++){
q=p;
q.x=p.x+a[i][0];
q.y=p.y+a[i][1];
q.time++;
if(q.x>=1&&q.x<=n&&q.y>=1&&q.y<=m&&map[q.x][q.y]!='*'&&q.time<t){
if(q.x==ex&&q.y==ey){
printf("%d\n",q.time);
return;
}
// if(q.time>t) continue;
if(map[q.x][q.y]>='a'&&map[q.x][q.y]<='z'){
xx=(1<<(map[q.x][q.y]-'a'));
q.nkey|=xx;
if(!vis[q.x][q.y][q.nkey]){
vis[q.x][q.y][q.nkey]=1;
Q.push(q);
}
}
else if(map[q.x][q.y]>='A'&&map[q.x][q.y]<='Z'){
xx=(map[q.x][q.y]-'A');
if(((q.nkey>>xx)&1)&&!vis[q.x][q.y][q.nkey]){
vis[q.x][q.y][q.nkey]=1;
Q.push(q);
}
}
else if(!vis[q.x][q.y][q.nkey]){
vis[q.x][q.y][q.nkey]=1;
Q.push(q);
}
}
}
}
printf("-1\n");
}
int main(){
int i,j,k=0;
while(~scanf("%d %d %d",&n,&m,&t)){
// if(k!=0)
// cout<<endl;
// k++;
for(i=1;i<=n;i++){
getchar();
for(j=1;j<=m;j++){
scanf("%c",&map[i][j]);
if(map[i][j]=='@'){
fx=i;
fy=j;
}
else if(map[i][j]=='^'){
ex=i;
ey=j;
}
}
}
memset(vis,0,sizeof(vis));
bfs();
}
return 0;
}