孙悟空救师傅
链接:https://ac.nowcoder.com/acm/problem/235903 来源:牛客网
师傅又被妖怪抓走了。师傅被困的宫殿可以看作一个 n×nn\times nn×n 的由字符构成的矩阵,每一个字符表示一个房间。字符'K'表示孙悟空的起始位置,'T'表示师傅被困的位置,'S'表示有蛇的房间,'.'表示空房间,'#'表示无法进入的房间。矩阵中包含且仅包含一个'K'和一个'T'。
每分钟,孙悟空都可以上下左右移动一格,如果遇到蛇,打倒蛇需要额外花费一分钟,保证地图上最多有五个有蛇的房间。此外孙悟空还需要集齐所有种类的钥匙才能救出师傅。钥匙的种类以 1,2,...,m1,2,...,m1,2,...,m 的顺序编号,且钥匙需要按照顺序拿。具体来说,孙悟空能拿第 iii 种钥匙,当且仅当对于 ∀j,1≤j<i\forall j, 1\le j\lt i∀j,1≤j<i 且 jjj 种类的钥匙都已经拿到至少一把。除了'#'的房间,其它所有房间都可以经过。孙悟空想要尽快救出师傅,你能帮帮他吗。
做法
首先数一下这里要处理的东西,必须按顺序拿到m把钥匙,第一次遇到S时需要多停留一秒(不确定是不是第一次),然后就是不能直接标记走过的路。钥匙的拿取比较好想到,我们用一个变量表示当前拿的是几号钥匙,当下一个标号的钥匙出现时才能去拿。那么就是考虑怎么在不mle的情况下标记出走过S房间的情况和怎么·尽量少往队列里面放东西。这里我们就不把状态数放进队列里面考虑,我们能更新答案的情况就是到达师傅那里时,已经拿到了m把钥匙,那么,就算我有无数种情况都能到,我也优先选择步数最短的情况,所以不需要去计算一些useless的状态,我们另开一个三维数组,表示在拿到k把钥匙的情况下走到坐标x,y的最短步数,而我们需要更新数组的情况只有当我们走到S时,下一步情况的数组步数大于上一步的步数+2,我们把他更新为上一步的步数+2,或者没有走到S,但下一步在数组的步数大于上一步(这一步,相对下一步的上一步,上同),更新数组,其他情况就不需要操作,只有当我们修改数组时才把相应状态放进队列即可。所以一开始的三维数组要初始化一个较大的值。(ps:上面的写法大体没错,但之后成功被qcjj hack,原因是第二次经过S的情况没有处理导致每一次走到S都会多停留1秒,所以当我们走到S后,将S修改为‘.’即可,更正一下之前题解的错误) 注意我们是bfs,所以第一次满足条件的一定是最小值,如果不及时停止可能会导致错误(没理解)
//本题代码
#include<bits/stdc++.h>
#define endl "\n"
#define ll long long
/*inline __int128 read(){
__int128 x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9'){
if(ch == '-')
f = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9'){
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
inline void print(__int128 x){
if(x < 0){
putchar('-');
x = -x;
}
if(x > 9)
print(x / 10);
putchar(x % 10 + '0');
}*/
//dont forget to check long long
//别写重变量名
//记得判越界
//别死磕
//处理字符串删掉关流
//用__int128时记得删掉关流
int vis[110][110][100];
struct node
{
int pos,key;
};
int n,m,sx=0,sy=0,edx=0,edy=0,ans=0;
int d[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
char s[110][110];
std::queue<node> q;
int bfs()
{
q.push((node){sx*n+sy,0});
vis[sx][sy][0]=0;
while(!q.empty())
{
auto t=q.front();
q.pop();
int x=t.pos/n,y=t.pos%n;
int cnt=t.key;
if(s[x][y]=='T'&&cnt==m)
{
//std::cout<<vis[x][y][cnt]<<endl;
return vis[x][y][cnt];
}
// std::cout<<x<<" "<<y<<" "<<cnt<<endl;
for(int i=0;i<4;i++)
{
int dx=x+d[i][0];
int dy=y+d[i][1];
int dcnt=cnt;
if(dx<0||dy<0||dx>=n||dy>=n||s[dx][dy]=='#') continue;
if(s[dx][dy]>='0'&&s[dx][dy]<='9'&&(s[dx][dy]-'0'-1)==dcnt) dcnt+=1;
if(s[dx][dy]=='S')
{
if(vis[dx][dy][dcnt]>vis[x][y][cnt]+2) {
s[dx][dy]='.';
vis[dx][dy][dcnt]=vis[x][y][cnt]+2;
q.push((node){dx*n+dy,dcnt});
}
}
else
{
if(vis[dx][dy][dcnt]>vis[x][y][cnt]+1) {vis[dx][dy][dcnt]=vis[x][y][cnt]+1;
q.push((node){dx*n+dy,dcnt});}
}
}
}
return -1;
}
void slove()
{
std::cin>>n>>m;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
std::cin>>s[i][j];
if(s[i][j]=='K')
{
sx=i;
sy=j;
}
else if(s[i][j]=='T')
{
edx=i;
edy=j;
}
}
}
memset(vis,0x3f,sizeof(vis));
ans=bfs();
if(ans==-1) std::cout<<"impossible"<<endl;
else std::cout<<ans<<endl;
//std::cout<<sx<<" "<<sy<<" "<<edx<<" "<<edy<<endl;
}
int main()
{
int T=1;
//std::cin>>T;
while(T--) {
slove();
}
return 0;
}