Codeforces 429B Working out(动态规划)解题报告

2016-09-27 2,225 次浏览 解题报告

题目链接

题目大意

两个人在一个有 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;
}

bLue 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处。
本文地址:https://dreamer.blue/blog/post/2016/09/27/codeforces-429b.dream

还不快抢沙发

添加新评论