Gym 101617D Jumping Haybales

imgimg

题意

​ 给出一个只由#和.组成的图,其中不能走到#上,但是可以跳过,而.是空地,可以随便走。现要求从左上角走到右下角,可以的话输出最少步数,否则输出-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;
}

​ 其实这种题在比赛的时候是能写出来的,就是没有这种思维方式。。

posted @ 2017-12-14 22:24  Refrain_Li  阅读(147)  评论(0编辑  收藏  举报