Codeforces 1353F Decreasing Heights(dp)
题意
100*100的网格,每个格子有一个初始值,每次操作可以使一个格子的数-1,问你最少多少次操作后存在一条(只往右和下的)(从左上角到右下脚每格递增1的)路径。
格子权值至多1e15,保证答案存在
思路
路径长度显然是固定的,如果路径中有一个基准,那么每个格子应该是多少也是确定的
而路径中一定是有一个格子不操作的,因为如果所有格子都操作,显然有至少少操作n+m-1次也符合题意的答案
那么我们可以枚举这个不操作的并且在路径中的格子
由于它不操作并且在路径中,所以我们可以推出(1,1)的目标值,以及其他所有格子的目标值
进行dp即可,注意如果当前值比目标值小,这个格子是一定不在路径中的
代码
int n,m;
ll a[101][101];
ll f[101][101];
int main() {
int t;
scanf("%d", &t);
mem(f,0x3f);
while(t--){
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
scanf("%lld", &a[i][j]);
}
}
ll ans = INF;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
ll bs = a[i][j]-i-j+2;
for(int l = 1; l <= n; l++){
for(int r = 1; r <= m; r++){
if(a[l][r]>=bs+l+r-2)f[l][r]=a[l][r]-bs-l-r+2;
else f[l][r]=INF;
}
}
for(int l = 1; l <= n; l++){
for(int r = 1; r <= m; r++){
if(l+r!=2)f[l][r]+=min(f[l-1][r],f[l][r-1]);
if(f[l][r]>INF)f[l][r]=INF;
}
}
ans=min(ans,f[n][m]);
}
}
printf("%lld\n",ans);
}
return 0;
}