題目鏈接
題目大意
兩個人在一個有 n×m 個房間的健身房內健身,每個房間都有一個鍛鍊可消耗的卡路里數。一個人從 a[1][1] 一路鍛鍊到 a[n][m] ,每次只能從 a[i][j] 移動到 a[i+1][j] 或 a[i][j+1];另一個從 a[n][1] 一路鍛鍊到 a[1][m],每次只能從 a[i][j] 移動到 a[i][j+1] 或 a[i-1][j] 。每在一個房間鍛鍊可以消耗對應的卡路里數,兩個人必須在中間的某一個房間碰面且只能碰面一次,這個房間不計算卡路里數。求兩人如何走,能使兩人總計消耗卡路里數最大。
解題思路
非常巧妙的 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;
}