F. Decreasing Heights(DP&贪心)
传送门
因为目标路径肯定是如上图形式,所以我们可以预处理每个坐标的高度.
从下标
开始让
,因为起点
的
.)
这样就从走高度加1层的点变成了走到同高度的点。
根据贪心的思想,最终高度的值肯定是在后来的
里面取。所以枚举
个点的高度为最终高度,进行从左上角到右下角的
即可。
时间复杂度:
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N =1e2+5;
const ll inf= 0x3f3f3f3f3f3f3f3f;
ll a[N][N],b[N][N],dp[N][N];
int t,n,m;
ll fun(int x,int y){//枚举最终地图路径的值为a[x][y]
for(int i=0;i<n;i++)
for(int j=0;j<m;j++){
b[i][j]=a[i][j]-a[x][y],dp[i][j]=inf;//b[i][j]表示到达(i,j)需要进行多少次操作.
}
if(b[0][0]<0||b[n-1][m-1]<0) return inf;//剪枝.
dp[0][0]=b[0][0];
for(int i=0;i<n;i++)//简单dp
for(int j=0;j<m;j++){
if(b[i][j]<0) continue;//该点走不了就跳过.
if(i&&b[i-1][j]>=0) dp[i][j]=min(dp[i][j],dp[i-1][j]+b[i][j]);
if(j&&b[i][j-1]>=0) dp[i][j]=min(dp[i][j],dp[i][j-1]+b[i][j]);
}
return dp[n-1][m-1];
}
int main(){
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
for(int j=0;j<m;j++) scanf("%lld",&a[i][j]),a[i][j]-=(i+j);//避免考虑要走到+1层.
ll ans=inf;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++){
ans=min(ans,fun(i,j));
}
printf("%lld\n",ans);
}
return 0;
}