P6855「EZEC-4.5」走方格 TJ
前言
题目传送门
正解:动态规划
挺 duliu 一道题,难度较大 qwq。
PS:因为此篇题解前后改动较多,如果有什么错误请各位奆佬提出,本蒟蒻感激不尽 awa。
题意简述
给你一个
法一:时间复杂度 Θ(m^2n^2) (TLE)
这但凡是个正常人都会想到吧……前两层循环枚举变为
结果,被校 OJ 卡了没骗到分。
Code
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int m,n,t,a[2005][2005];
ll ans=LONG_LONG_MAX,dp[2005][2005];
int main(){
scanf("%d %d",&m,&n);
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
scanf("%d",&a[i][j]);
}
}
for(int x=1;x<=m;x++){
for(int y=1;y<=n;y++){
memset(dp,0,sizeof(dp));
t=a[x][y];
a[x][y]=0;
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
dp[i][j]=max(dp[i][j-1],dp[i-1][j])+a[i][j];
}
}
ans=min(ans,dp[m][n]);
a[x][y]=t;
}
}
printf("%lld",ans);
return 0;
}
法二:正解,时间复杂度 Θ(mn)
PS * 2:因为 me 习惯用
m 表示行n 表示列,所以下列题解就会这么写。
有点麻烦。
如果每个点只能遍历一次,那么必须不变值和变为
首先我们可以考虑先求出从
这两个数组很好求,按照每个初学 DP 者都要打的取数板子就珂以了。至于为什么要求这两个数组,我先卖个关子,待会儿就知道了(逃。
我们知道,如果你从
-
从左边绕。
-
从上边绕。
给这两种方法更严谨的定义
-
从左边绕:经过点
(x,y-i) 。 -
从上边绕:经过点
(x-i,y) 。
对于这两种情况,我们可以分别用两个二维数组
但是如何求这两个数组呢?
直接切入可能比较麻烦。这个时候我们可以先分析这种情况:
不管是往哪边绕,也不管前面怎么走,都紧贴着点
首先分析从左边绕的情况。
看图,蓝色区域表示从
如果这么算,那么从点
现在大家知道两个
那我们现在只求了最贴近点
我们之前不是用了一个数组来存往左边绕的值吗?因为循环的顺序是从上到下,从左到右的,所以在求点
那么最后的结果就是:
至于为什么我们利用的是
从上面绕分析方法也差不多,这里不多说画张图让读者感知一下。
(您看看这两张图多像,连大小都差不多26 KB)
最后求出
最后求答案有些麻烦,因为题目要求的是变化后最能获得的最大分数的最小值,所以
首先每对一个格子进行操作,最后得到的答案会是下列三种情况中的一种:
-
从左边绕过去得到的最大分数。
-
从上边绕过去得到的最大分数。
-
经过这个格子得到的最大分数。
前两个我们已经求解了,但其实第三种情况是灰常简单的!因为要保证经过点
所以最后的答案终于可能被更新了 owo:
最后再强调一遍要注意最大值和最小值别用反了啊! 别问我为什么知道(悲)。
Code
#include<bits/stdc++.h>
#define ll long long //记得要开long long哦!
using namespace std;
//温馨提示细节:因为最后答案还是求的最小值,所以 ans 需要定义极大值
ll m,n,ans=LONG_LONG_MAX,a[2005][2005],dp1[2005][2005],dp2[2005][2005],l[2005][2005],d[2005][2005];
int main(){
//输入
scanf("%lld %lld",&m,&n);
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
scanf("%lld",&a[i][j]);
}
}
//求两个 dp 数组的值
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
dp1[i][j]=max(dp1[i-1][j],dp1[i][j-1])+a[i][j];
}
}
for(int i=m;i;i--){
for(int j=n;j;j--){
dp2[i][j]=max(dp2[i+1][j],dp2[i][j+1])+a[i][j];
}
}
//核心代码开始
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
l[i][j]=max(l[i][j-1],dp1[i][j-1]+dp2[i+1][j-1]);
d[i][j]=max(d[i-1][j],dp1[i-1][j]+dp2[i-1][j+1]);
ans=min(ans,max(max(l[i][j],d[i][j]),dp1[i][j]+dp2[i][j]-2*a[i][j]));
}
}
//核心代码结束,输出答案
printf("%lld",ans);
return 0;
}
写在最后
这真的是一道很好的动态规划题,很考验思维,也有很多需要注意的细节。最后,看在本人写了那么久的份上,就请您随手点一下左下角那个小小的赞吧 qwq。