hihocoder1328
题解:这一题还是挺不错的,不是常规的BFS求最短路,而要加上钥匙的状态压缩。共三个状态。
因为k<=5,钥匙的状态进行状态压缩,用v[x][y][k]表示在坐标(x,y)身上钥匙状态为k的步数
每次走到有钥匙的地方,那么更新钥匙状态;走到锁的地方,判断是否有开这把锁的钥匙。
代码:
#include <bits/stdc++.h>
using namespace std;
int const N = 100 + 10;
char mp[N][N];
int n,m,k,sx,sy,ex,ey;
int v[N][N][1<<6]; //现在在坐标(x,y)身上钥匙状态为k的步数
int dir[4][2] = {0,1,1,0,0,-1,-1,0};
struct Node
{
int x,y,sum;
};
queue<Node>q;
int bfs(){
q.push((Node){sx,sy,0});
v[sx][sy][0] = 0;
while(!q.empty()){
Node p = q.front(); q.pop();
if(p.x == ex && p.y == ey) return v[ex][ey][p.sum];
for(int i=0;i<4;i++){
int x = p.x + dir[i][0], y = p.y + dir[i][1];
if(x<0||y<0||x>=n||y>=m||mp[x][y]=='#') continue;
if('0'<=mp[x][y]&&mp[x][y]<'5'){ //如果下一步是钥匙存放的地方
int sum = p.sum | 1<<(mp[x][y]-'0'); //更新钥匙的状态
if(!v[x][y][sum]){ //如果之前没有这个状态
v[x][y][sum] = v[p.x][p.y][p.sum] + 1; //步数加一
q.push((Node){x,y,sum});
}
}else if('A'<=mp[x][y]&&mp[x][y]<='Z'){ //如果是锁
if(p.sum&(1<<(mp[x][y]-'A'))){ //如果携带了这一把钥匙
if(!v[x][y][p.sum]){
v[x][y][p.sum] = v[p.x][p.y][p.sum] + 1;
q.push((Node){x,y,p.sum});
}
}
}else{ //如果下一步是路
if(!v[x][y][p.sum]){
v[x][y][p.sum] = v[p.x][p.y][p.sum] + 1;
q.push((Node){x,y,p.sum});
}
}
}
}
return -1;
}
int main(){
cin>>n>>m>>k>>sx>>sy>>ex>>ey;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
cin>>mp[i][j];
for(int i=0;i<k;i++){
int x,y;
cin>>x>>y;
mp[x][y] = '0' + i; //表示此处有要是i
}
printf("%d\n",bfs());
return 0;
}