题意:从左上角到右下角,‘#’不能落脚,每次可以向下或者向右跳小于等于k的距离,问最小需要多少步到达右下角
分析:设dp[i][j]表示到达点坐标点(i),(j)所需的最少步数,状态见代码
AC_Code:
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 #define endl ' ' 5 const int maxn=2e3+10; 6 const int inf=0x3f3f3f3f; 7 8 char s[maxn][maxn]; 9 int n,k; 10 int dp[maxn][maxn]; 11 int c[maxn],r[maxn]; 12 13 int main() 14 { 15 scanf("%d%d",&n,&k); 16 for(int i=0;i<n;i++){ 17 scanf("%s",s[i]); 18 } 19 if( s[0][0]=='#'){ 20 printf("-1 "); 21 return 0; 22 }else if( s[n-1][n-1]=='#'){ 23 printf("-1 "); 24 return 0; 25 } 26 27 memset(dp,inf,sizeof(dp)); 28 29 memset(r,0,sizeof(r)); 30 memset(c,0,sizeof(c)); 31 32 dp[0][0]=0; 33 34 for(int i=0;i<n;i++){ 35 for(int j=0;j<n;j++){ 36 if( s[i][j]=='#' ) continue; 37 for( ;r[i]<j;r[i]++){ 38 if( s[i][r[i]]=='.' && j-r[i]<=k ) break;//为什么到第一个距离小于k且是点的地方就可以break呢,因为只能往东往南走,后面的小于k且是点的步数到达步数一定是大于等于第一个步数的 39 } 40 dp[i][j]=min(dp[i][j],dp[i][r[i]]+1); 41 for( ;c[j]<i;c[j]++){ 42 if( s[c[j]][j]=='.' && i-c[j]<=k) break; 43 } 44 dp[i][j]=min(dp[i][j],dp[c[j]][j]+1); 45 if( dp[c[j]][j]>=dp[i][j] ) c[j]=i; 46 if( dp[i][r[i]]>=dp[i][j] ) r[i]=j; 47 } 48 } 49 50 if( dp[n-1][n-1]!=inf ){ 51 printf("%d ",dp[n-1][n-1]); 52 }else{ 53 printf("-1 "); 54 } 55 }