Gym 101617D Jumping Haybales
题意
给出一个只由#和.组成的图,其中不能走到#上,但是可以跳过,而.是空地,可以随便走。现要求从左上角走到右下角,可以的话输出最少步数,否则输出-1。数据的输入第一行是n和k,n表示n*n的图,k表示一次最多走的步数。
解题思路
开始的时候把k的含义理解错了,以为是最多走多少个.。然后就想用BFS,毕竟涉及到了最少步数,但是BFS的时间复杂度是n^2*k,妥妥的超。然后想到了dijkstra,但是建图的时间复杂度就TLE了。之后还往并查集、记忆化搜索想了想,但是没写出来。后来看了大佬的题解,woc,真的是太巧妙了。
主要思想是:枚举每个.(空地),他用到了两个一维数组hor,ver,分别是是用来存遍历到当前节点时,由它之前节点跳过来的最优下标。枚举的时候每次在更新每个节点最少步数的同时更新hor和ver。就这样一直递推到右下角。
代码
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
#define maxn 2005
#define inf 0x3f3f3f3f
char pic[maxn][maxn];
int hor[maxn],ver[maxn],d[maxn][maxn];//hor代表到当前点为止第i行的到此处的最优位置(ver则代表列)。
int n,k;
int main()
{
//freopen("in.txt","r",stdin);
while(~scanf("%d%d",&n,&k))
{
for(int i=0; i<n; i++)
scanf("%s",pic[i]);
memset(hor,0,sizeof(hor));
memset(ver,0,sizeof(ver));
memset(d,inf,sizeof(d));
d[0][0]=0;
for(int i=0; i<n; i++)
for(int j=0; j<n; j++)
{
if(pic[i][j]=='#') continue;
for(; hor[i]<j; hor[i]++)
if((j-hor[i])<=k&&pic[i][hor[i]]=='.') break; //找到到达这里的最优点,有点贪心的思想,走最远的路(下同)。
d[i][j]=min(d[i][j],d[i][hor[i]]+1); //更新最少步数(下同)
for(; ver[j]<i; ver[j]++)
if((i-ver[j])<=k&&pic[ver[j]][j]=='.') break;
d[i][j]=min(d[i][j],d[ver[j]][j]+1);
if(d[i][j]<=d[i][hor[i]]) hor[i]=j;//开始的时候我把这一行写到了上个循环的上面,这样是错的,因为状态是二维的,有可能在第二个循环更新d[i][j]。
if(d[i][j]<=d[ver[j]][j]) ver[j]=i;
}
if(d[n-1][n-1]==inf) puts("-1");
else printf("%d\n",d[n-1][n-1]);
}
return 0;
}
其实这种题在比赛的时候是能写出来的,就是没有这种思维方式。。