题意
一个n*m的矩阵,每一个位置都有一定的高度,要求从(1,1)走到(n,m)并且每次移动只能向下或者向右移动,并且要求只能向比自己高度高1的位置移动。定义一个操作:执行一次可以使得任意一个格子的额高度减一,问从1,1到n,m操作的最少次数。
分析
考虑如果不做操作,就是一道很经典的dp,所以现在需要确定的是,操作结束之后的矩阵。
(1)首先一定会有一个格子的高度保持不变
(2)由起点的高度可以推得所有格子的高度
(3)所以我们枚举高度不变的格子,依据他计算出起点高度,之后枚举起点高度即可
(4)该题为经典DP变形
代码
#define int ll
int a[111][111],dp[111][111];
void solve()
{
int n,m;cin>>n>>m;
set<int>aa;
rep(i,n) rep(j,m)
{
cin>>a[i][j];
if(a[i][j]-i-j<=a[0][0]) aa.insert(a[i][j]-i-j);
}
ll ans=1e18;
for(auto x:aa)
{
rep(i,n) rep(j,m) dp[i][j] = 1e18;
dp[0][0] = a[0][0]-x;
rep(i,n) rep(j,m)
{
int need = a[i][j] - (x+i+j);
if(need>=0&&i)
dp[i][j]=min(dp[i][j],dp[i-1][j]+need);
if(need>=0&&j)
dp[i][j]=min(dp[i][j],dp[i][j-1]+need);
}
ans=min(ans,dp[n-1][m-1]);
}
cout<<ans<<endl;
}