每日刷题:lightoj-1004 - Monkey Banana Problem

终于开始写人生第一道DP了。
第一题,耳熟能详的猴子吃香蕉问题。
题目的话,就不放出来了,去lightoj上就能找到。
在一个菱形中找到一条路径,使得猴子能吃到的香蕉数最多。
看下图,题目比较容易想到,用一个相同的表记录走到某一个为止能吃到的香蕉数,每次决策取最大的就是了。
实际编程时,我们是以二维数组来填表的,所以请把下图想象成一个实心右箭头’>’样子的三角形


这里写图片描述

7  0  0  0
6  4  0  0
2  5  10 0
9  8  12 2
2  12 7  0
8  2  0  0
10 0  0  0

我们定义
input[i][j]:第i行第j列的格子所拥有的香蕉数,
dp[i][j]:走到第i行第j列的格子可以吃到的最大香蕉总数。
菱形的行数:2*N-1
最终dp[2*N-2][0],保存的值就是答案
则从头往下递推可以得到下面的状态转移方程

dp[i][j]=input[i][j]input[i][j]+dp[i1][j]input[i][j]+max(dp[i1][j1],dp[i1][j])input[i][j]+max(dp[i1][j],dp[i1][j+1])

①: j=i=0
②: j=0,0<i<N
③: 0<j<i,0<i<N
④: i>=N
上面的状态有点多,如果我们换一种方式

0 7  0  0  0
0 6  4  0  0
0 2  5  10 0
0 9  8  12 2
0 2  12 7  0
0 8  2  0  0
0 10 0  0  0

则②的转移可以合并成③

以下是第一种状态转移的代码,代码规范就请忽略吧。第二种状态转移的实现就不写了,网上也能找到别的大神的实现。虽然AC了,但待优化的地方还有很多。

#include <iostream>
#include <cstdio>
#include <math.h>
#include<memory.h> 
using namespace std;
int main() {
    int N, caseno = 0, cases;
    scanf("%d", &cases);
    while( cases-- ) {
        cin>>N;
        long long input[2*N-1][N];//输入
        long long dp[2*N-1][N]; 

        memset(input,0,sizeof(input));
        memset(dp,0,sizeof(dp));

        for(int i=0;i<2*N-1;i++)
        {
            if(i<N)
            {

                for(int j=0;j<=i;j++)
                {
                    cin>>input[i][j];
                }
            }
            else
            {
                for(int j=0;j<2*N-i-1;j++)
                {
                    cin>>input[i][j];
                }
            }
        }
    /*  for(int i=0;i<2*N-1;i++)//测试输出 
        {
            for(int j=0;j<N;j++)
            {
                cout<<input[i][j]<<" ";

            }
            cout<<endl;
        }
        */
        //DP递推
        dp[0][0] = input[0][0];//初始条件
        dp[0][2] = 0;

        for(int i=1;i<2*N-1;i++)
        {
            if(i<N)
            {
                for(int j=0;j<=i;j++)
                {
                    if(j==0)
                    {
                     dp[i][j]=input[i][j]+dp[i-1][j];
                    }
                    else 
                    {
                       dp[i][j] = input[i][j] + max(dp[i-1][j-1],dp[i-1][j]);   
                    }
                }
            }
            else
            {
                for(int j=0;j<2*N-i-1;j++)
                {
                    dp[i][j]=input[i][j] + max(dp[i-1][j],dp[i-1][j+1]);
                }
            }
        }
    /*  for(int i=0;i<2*N-1;i++)//测试输出 
        {
            for(int j=0;j<N;j++)
            {
                cout<<dp[i][j]<<" ";

            }
            cout<<endl;
        }*/
        cout<<"Case "<<++caseno<<": "<<dp[2*N-2][0]<<endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值