题目链接
题目大意
两个人在一个有 n×m 个房间的健身房内健身,每个房间都有一个锻炼可消耗的卡路里数。一个人从 a1 一路锻炼到 an ,每次只能从 ai 移动到 ai+1 或 ai;另一个从 an 一路锻炼到 a1,每次只能从 ai 移动到 ai 或 ai-1 。每在一个房间锻炼可以消耗对应的卡路里数,两个人必须在中间的某一个房间碰面且只能碰面一次,这个房间不计算卡路里数。求两人如何走,能使两人总计消耗卡路里数最大。
解题思路
非常巧妙的 DP 题,进行一些转化后可以使难度大大降低。题目原意是求两人从起点走到终点的最大消耗卡路里路径且必须碰面一次,由于一条确定的路径上消耗的卡路里数只与经历的房间有关,与方向无关,所以每一人的路径我们都可以拆分成两部分,即从起点到碰面点,以及从终点到碰面点。这样,问题就转化为了从四个角到碰面点的 DP 。按照求数字三角形的方法求出四个起点的 DP,然后枚举所有的碰面点,求出四条路径到碰面点的最大卡路里数即可。
参考代码
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAX = 1001;
int n, m;
int a[MAX][MAX], dp1[MAX][MAX], dp2[MAX][MAX], dp3[MAX][MAX], dp4[MAX][MAX];
int main(int argc, char const *argv[]) {
scanf("%d %d", &n, &m);
for(int i=1; i<=n; ++i) {
for(int j=1; j<=m; ++j) {
scanf("%d", &a[i][j]);
}
}
// 计算以四个角为起点的四个 DP
for(int i=1; i<=n; ++i) {
for(int j=1; j<=m; ++j) {
dp1[i][j] = max(dp1[i-1][j], dp1[i][j-1]) + a[i][j];
}
}
for(int i=1; i<=n; ++i) {
for(int j=m; j>=1; --j) {
dp2[i][j] = max(dp2[i-1][j], dp2[i][j+1]) + a[i][j];
}
}
for(int i=n; i>=1; --i) {
for(int j=1; j<=m; ++j) {
dp3[i][j] = max(dp3[i+1][j], dp3[i][j-1]) + a[i][j];
}
}
for(int i=n; i>=1; --i) {
for(int j=m; j>=1; --j) {
dp4[i][j] = max(dp4[i][j+1], dp4[i+1][j]) + a[i][j];
}
}
// 枚举所有碰面点,求最大值
int ans = 0;
for(int i=2; i<n; ++i) {
for(int j=2; j<m; ++j) {
ans = max(ans, dp1[i-1][j]+dp2[i][j+1]+dp3[i][j-1]+dp4[i+1][j]);
ans = max(ans, dp1[i][j-1]+dp2[i-1][j]+dp3[i+1][j]+dp4[i][j+1]);
}
}
printf("%d\n", ans);
return 0;
}
还不快抢沙发