LightOJ 1004 Monkey Banana Problem

LightOJ 1004
题意:
题目给了一张地图,地图上的数字表示猴子走到这点后能够取得的香蕉数目,猴子只能从自己当前位置向下一行的相邻位置转移,求得到最多的香蕉的数量
这里写图片描述
这道题跟数字三角形是一个意思的,只是这道题的走的图形不是一个三角形而是菱形,菱形相当于一个正的三角形和一个倒着的三角形拼接而成的。
我们来看菱形的上部分,用dp[i][j]表示在i,j位置得到的最大的香蕉数量.
如果从上往下推:不难发现对于每个边缘的位置,只能从它的上一行的一个位置推下来,比如dp[2][1]位置,只能由dp[1][1]走下来,而dp[3][3]只能由dp[2][2]走下来,而除了dp[i][1]和dp[i][i]这样的边界位置,其余的位置都是由上一行的相邻两个位置推出的,这就涉及到了边界处理
转移方程为:
if(j == 1) dp[i][j] = dp[i - 1][j] + map[i][j];
if (j == i) dp[i][j] = dp[i - 1][j - 1] + map[i][j];
else dp[i][j] = max(dp[i - 1][j - 1], dp[i - 1][j]) + map[i][j];

如果倒着推:不难发现,对于每一个元素,都是由下一行的两个相邻位置转移过来的, 所以不存在边界处理,我想这就是为啥在做数字三角形的时候,大佬们选择倒推的原因吧。。。
转移方程为:
dp[i][j] = max(dp[i + 1][j], dp[i + 1][j + 1]) + map[i][j];

很不幸,这道题不管是正着推还是倒推,都会涉及边界处理,因为这有一个倒着的三角形~ 这个倒着的三角形处理实际上跟上面讲的一样,不过如果正三角形是正推那倒三角形就倒推,如果正三角形倒推那倒三角形就正推啦~

下面附上AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int T, N;
const int MAXN = 1e2 + 10;
int map[MAXN * 2][MAXN];
int dp[MAXN * 2][MAXN];
void input() {  //输入数据
  for (int i = 1; i <= N; i++) {
    for (int j = 1; j <= i; j++) {
      cin >> map[i][j];
    }
  }
  for (int i = N + 1; i <= 2 * N - 1; i++) {
    for (int j = 1; j <= 2 * N - i; j++) {
      cin >> map[i][j];
    }
  }
}
int main() {
  scanf("%d", &T);
  int Case = 0;
  while (T--) {
    cin >> N;
    input();
    memset(dp, 0, sizeof dp); 
    //初始赋值
    dp[2 * N - 1][1] = map[2 * N - 1][1];
    //我是选择的从最后往前推,倒三角形包含边界处理
    for (int i = 2 * N - 2; i >= N; i--) {
      for (int j = 1; j <= 2 * N - i; j++) {
        if (j == 1) dp[i][j] = dp[i + 1][j] + map[i][j];
        else if (j == 2 * N - i) dp[i][j] = dp[i + 1][j - 1] + map[i][j];
        else dp[i][j] = max(dp[i + 1][j], dp[i + 1][j - 1]) + map[i][j];
      }
    }
    for (int i = N - 1; i >= 1; i--) {
      for (int j = 1; j <= i; j++) {
        dp[i][j] = max(dp[i + 1][j], dp[i + 1][j + 1]) + map[i][j];
      }
    }
    cout << "Case " << ++Case << ": ";
    cout << dp[1][1] << endl;
  }
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值