题意:
某个魔法师被锁在了一个建筑物里。这建筑物有H行,每行有W个房间。用A[i][j]表示某个房间的状态:当A[i][j]=’#’时房间被锁,不能进入;当A[i][j]=’.’时房间可以进入。魔法师当前所在房间状态为’S’(保证没有出口)。在第1行、第1列、第H行和第W列的房间有出口。房间(i,j)可以到达(i+1,j),(i,j+1),(i-1,j),(i,j-1).魔法师要用魔法使自己到达一个有出口的房间,在每一次魔法中,他会这样操作:
1.移动到相邻的、可以进入的房间,最多K步(可以是0)。
2.然后解锁最多K个房间(可以是0)。这些房间将会一直解锁。
求魔法师需要的最少的魔法次数。
题解:可以发现,除了第一次第一步需要单独计算,接下来的步骤就是将下一次打算走的路线上被锁的房间解锁然后再走,所以以后都不会碰到上锁的房间。所以求出第一次走最多K步可以到达的房间,再计算离该房间最近的出口所需次数即可。
代码:
#include<cstdio>
#include<queue>
#include<cstring>
#define maxn 805
#define INF 0x3f3f3f3f
using namespace std;
typedef pair<int,int> PII;
int h,w,k,dist[maxn][maxn],sx,sy,d[5]={0,1,0,-1,0},ans=INF;
char s[maxn][maxn];
queue<PII> q;
int Get(int i,int j)
{
int tmp=(i+k-2)/k;
tmp=min(tmp,(j+k-2)/k);
tmp=min(tmp,(h-i+k-1)/k);
tmp=min(tmp,(w-j+k-1)/k);
return tmp;
}
int main()
{
scanf("%d%d%d",&h,&w,&k);
for(int i=1;i<=h;i++) scanf("%s",s[i]+1);
for(int i=1;i<=h&&!sx;i++)
for(int j=1;j<=w&&!sx;j++)
if(s[i][j]=='S') sx=i,sy=j;
memset(dist,0x3f,sizeof(dist));
dist[sx][sy]=0;
q.push(PII(sx,sy));
while(!q.empty())
{
int x=q.front().first,y=q.front().second;
q.pop();
if(dist[x][y]==k) continue;
for(int i=1;i<=4;i++)
{
int cx=x+d[i-1],cy=y+d[i];
if(cx<1||cy<1||cx>h||cy>w||dist[x][y]+1>=dist[cx][cy]||s[cx][cy]=='#') continue;
dist[cx][cy]=dist[x][y]+1; q.push(PII(cx,cy));
}
}
for(int i=1;i<=h;i++)
for(int j=1;j<=w;j++)
if(dist[i][j]<INF)
ans=min(ans,Get(i,j)+1);
printf("%d\n",ans);
}