power oj 1027 买花瓶(简单动态规划DP)

Description

john想买几个花瓶装饰一下新房。已知花店的花瓶被固定地排成一行并被依次排号,且花店有
一个原则,花瓶不能移动也不能挑选,只能买连号的花瓶。由于每个花瓶都有自己的美学价值,
请你帮john选出其中美学价值最大的一组。
比如,有六个花瓶,它们的美学价值分别是 3 -1 2 4 -6 5,那么john应该选3 -1 2 4(美学价值为8)
这一组。而不能挑2 3 4 5这一组(违犯),或是2 4组(美学价值为6,不是最大)。

Input

测试有很多次,对于每一次测试:
第一行为一个正整数 N( 1 <= N <=10000 ),代表花瓶的个数.当N=0时,代表测试结束;
第二行的N个整数Mi( -100 <= Mi <= 100 )分别代表每个花瓶的美学价值,其间用空格分开。

Output

每次测试输出一行,代表拥有最大美学价值的一组连号花瓶的美学价值MAX。

Sample Input

6
3 -1 2 4 -6 5
0

Sample Output

8


看懂了吗?其实就是问你把这堆数里面的那些数字加起来最大,而且所加的这些数字必须是连续的。

我一直忘记这个名字,要不就叫超级无敌最大连续求和子序列吧。

福哥起的名字,绝对没毛病!

那么这道题目,要怎么求呢?又是从哪里可以看出,这样子的题目,需要用dp呢?

先来理解一下这道题,第一眼看进去,你的思路是怎样的?

你是不是想过,一遍遍地遍历?对不对?因为一组数里面找最大的,找最小的,排序,for循环的遍历用的太熟练了,可是…,那样的复杂度太高。给你一堆数,你需要遍历多少遍的序列才能找到这样的序列?告诉我多少遍?我知道你想都不敢想…

所以包括下面所要说的各种dp问题,几乎都是,你看上去就想着遍历一下(我相信题目做多了之后会有那种很好的感觉,为了避免自己妄加猜测,就不要提前想了,就是讲一下怎么判断这道题是不是用dp的思想),所以不妨大胆的给自己提个醒,告诉自己,其实感觉想用遍历的感觉去做的题目,不妨试一试dp的思想

就像这道题,问你如何去找最大和的子序列,我们不妨想想dp。而dp包括那几个方面?最优子结构,状态转移方程和边界。所以,可以先想一下最优子结构是什么,也就是每一个状态是由什么状态决定的;然后可以写出状态转移方程,最后通过确定边界(也不知道这样的顺序是不是对的,也有可能今后会更正,至少我现在是按照这几个顺序来写的。)。

那么这道题呢?先想一想他的最优子结构是什么。也就是你随便给出一个状态,它是由哪个状态所决定的?(也要考虑所设定的dp数组的意义。)

根据感觉,我们定义一个一维的dp数组,假设dp[i]代表的是在从1~ i 之间,超级无敌最大连续求和子序列的和。

那么,对于dp[ i ]来说,肯定决定他的,只有两种情况:要么,加上前面的那个数地最大递增子序列的和,要么不加它(这个数加上前面的数就会变小,还不如自己一个数大)。

所以,现在就可以顺理成章地写出,
dp[ i ]=max(dp[ i - 1 ] + a[ i ] ,a [ i ] );

写状态转移方程的时候一定要注意:不仅仅要注意这个状态和上一个状态的联系,也要注意这一个状态和下一个状态的联系。

那么,边界呢?

边界无非就是从哪里开始的。说的很神秘的感觉,当时刚学的时候慌得一批。

无非就是dp[ 1 ]。

dp[ 1 ]等于a[ 1 ]就ok了。

那么,这道题的分析过程,就完了,下面粘上自己的AC代码.

#include<algorithm>
#include<cstdio>
#include<cmath>
#include<string.h>
#include<iostream>
typedef long long ll;
const int maxn=10010;
using namespace std;
ll m[maxn],dp[maxn];
int main()
{
    ll n;
    while(scanf("%lld",&n)!=EOF)
    {
        if(n==0)
            break;
 
        ll maxx=0;
        memset(dp,0,sizeof(dp));
 
        scanf("%lld",&m[1]);
        dp[1]=m[1];//边界
        for(ll i=2;i<=n;i++)
        {
            scanf("%lld",&m[i]);
 
            dp[i]=max(dp[i-1]+m[i],m[i]);//状态转移方程
 
            maxx=max(maxx,dp[i]);//选择最大的值
 
        }
        printf("%lld\n",maxx);//输出最大的那个dp[i]值就好了
 
    }
 
 
    return 0;
}

ok,我去打球了!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值