题目链接
给出n*n的图,’.’能走,’#’不能走,k为最多能跳远的距离,每次只能往右或者往下走,求左上角到右下角最短需要多少步数。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 2000+5;
const int inf = 0x3f3f3f3f;
char a[N][N];
int row[N], col[N], d[N][N];
int n, k;
void init()
{
for( int i = 0 ; i <= n ; i ++ ){
row[i] = col[i] = 0;
for( int j = 0 ; j <= n ; j ++ ){
d[i][j] = inf;
}
}
}
int main()
{
freopen("in.txt","r",stdin);
while( scanf("%d%d", &n, &k) != EOF ){
init();
for( int i = 0 ; i < n ; i ++ ){
scanf("%s",a[i]);
//printf("%s\n",a[i]);
}
d[0][0] = 0;
for( int i = 0 ; i < n ; i ++ ){
for( int j = 0 ; j < n ; j ++ ){
if( a[i][j] == '#' ) continue;
///维护最接近当前点d[i][j]的最小步数到达的列的位置下标
for( ; col[i] < j ; col[i] ++ )
if( j-col[i] <= k && a[i][col[i]] == '.' )
break;
d[i][j] = min( d[i][j], d[i][col[i]]+1 );
///同上
for( ; row[j] < i ; row[j] ++ )
if( i-row[j] <= k && a[row[j]][j] == '.' )
break;
d[i][j] = min( d[i][j], d[row[j]][j]+1 );
///维护最优值,或许一直能有最优值,也不需要下面这两行了
///max(row*col) = 2000*2000
///row[0~N] && col[0~N]无重复判断
///行列各维护一个数组 max(row*col) * 2
if( d[i][j] <= d[i][col[i]] ) col[i] = j;
if( d[i][j] <= d[row[j]][j] ) row[j] = i;
}
}
if( d[n-1][n-1] == inf ) printf("-1\n");
else printf("%d\n", d[n-1][n-1] );
}
return 0;
}