蒜国地域是一个 n 行 m 列的矩阵,下标均从 1 开始。蒜国有个美丽的城堡,在坐标 (n,m) 上,蒜头君在坐标 (1,1) 的位置上。蒜头君打算出发去城堡游玩,游玩结束后返回到起点。在出发去城堡的路上,蒜头君只会选择往下或者往右走,而在返回的路上,蒜头君只会选择往上或者往左走,每次只能走一格。已知每个格子上都有一定数量的蒜味可乐,每个格子至多经过一次。
现在蒜头君请你来帮他计算一下,如何计划来回行程,可以收集到最多的蒜味可乐。
输入格式
第一行输入两个整数 n,m(1≤n,m≤50),表示蒜国是一个 n 行 m 列的矩阵。
接下来输入 n 行,每行输入 m 个整数,代表一个 n×m 的矩阵,每个整数代表对应位置上的蒜味可乐数量,每行的每两个整数之间用一个空格隔开。其中蒜头君的位置和城堡的位置上没有蒜味可乐,用 0 表示,其余位置上的整数范围在 [1,100] 内。
输出格式
输出一行,输出一个整数,表示蒜头君在来回路上能收集到的蒜味可乐的最大值。
样例输入
3 3
0 2 9
4 8 6
2 7 0
样例输出
36
题解:这个题刚开始想的是这样,先从上往下走,再记录下父亲,最后消去父亲的值,再从下往上走,记录结果,得出答案,但是只能过两组。
#include<bits/stdc++.h>
using namespace std;
const int maxn=55;
int mapp[maxn][maxn];
int dp1[maxn][maxn];
int pre[maxn][maxn];
int dp2[maxn][maxn];
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&mapp[i][j]);
}
}
//right down
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(i==1&&j==1){
dp1[i][j]=0;
pre[i][j]=-1;
}else if(i==1){
dp1[i][j]=dp1[i][j-1]+mapp[i][j];
pre[i][j]=0;
}else if(j==1){
dp1[i][j]=dp1[i-1][j]+mapp[i][j];
pre[i][j]=1;
}else{
if(dp1[i-1][j]>dp1[i][j-1]){
dp1[i][j]=dp1[i-1][j]+mapp[i][j];
pre[i][j]=1;
}else{
dp1[i][j]=dp1[i][j-1]+mapp[i][j];
pre[i][j]=0;
}
}
}
}
int ans=dp1[n][m];
int tempr=n,tempc=m;
while(pre[tempr][tempc]!=-1){
if(pre[tempr][tempc]==1){
mapp[tempr-1][tempc]=0;
tempr=tempr-1;
}else if(pre[tempr][tempc]==0){
mapp[tempr][tempc-1]=0;
tempc=tempc-1;
}
}
for(int i=n;i>=1;i--){
for(int j=m;j>=1;j--){
if(i==n&&j==m){
continue;
}else if(i==n){
dp2[i][j]=dp2[i][j+1]+mapp[i][j];
}else if(j==m){
dp2[i][j]=dp2[i+1][j]+mapp[i][j];
}else{
dp2[i][j]=mapp[i][j]+max(dp2[i+1][j],dp2[i][j+1]);
}
}
}
ans+=dp2[1][1];
printf("%d\n",ans);
return 0;
}
最后得出的分析:不能先算出去的最大值,再算返回的最大值,这样可能导致只保证了去的最大值,但没有保证来回之和的最大值。也就是说,来回的优先级是相同的,如果先算去路的最大值就会使得去的优先级高于回的优先级。
最后,可以使用一个四维数组res[i][j][k][l]来表示路径1走到[i][j]和路径2走到[k][l]的和最优值。其中,因为走的步数相同,所以i+j=k+l(利用这个把空间和时间复杂度降一级),两条路径也不能用到一个点,最后写出状态转移方程:res[i][j][k][l]=max(max(res[i-1][j][k-1][l],res[i-1][j][k][l-1]),max(res[i][j-1][k-1][l],res[i][j-1][k][l-1]))+mapp[i][j]+mapp[k][l],最后答案啊自然也得改一下,因为最后都走到终点,所以cout<<max(max(res[n-1][m][n-1][m],res[n-1][m][n][m-1]),max(res[n][m-1][n][m-1],res[n][m-1][n-1][m]))<<endl;
#include<bits/stdc++.h>
using namespace std;
const int maxn=55;
int mapp[maxn][maxn],res[maxn][maxn][maxn][maxn];
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&mapp[i][j]);
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
for(int k=1;k<=n;k++){
for(int l=1;l<=m;l++){
if(i+j!=k+l){
continue;
}
if(i==k&&j==l){
continue;
}
res[i][j][k][l]=max(max(res[i-1][j][k-1][l],res[i-1][j][k][l-1]),max(res[i][j-1][k-1][l],res[i][j-1][k][l-1]))+mapp[i][j]+mapp[k][l];
}
}
}
}
cout<<max(max(res[n-1][m][n-1][m],res[n-1][m][n][m-1]),max(res[n][m-1][n][m-1],res[n][m-1][n-1][m]))<<endl;
return 0;
}