码迷,mamicode.com
首页 > 编程语言 > 详细

【算法学习笔记】71.动态规划 双重条件 SJTU OJ 1124 我把助教团的平均智商拉低了

时间:2015-07-10 18:59:44      阅读:148      评论:0      收藏:0      [点我收藏+]

标签:

这个题第一眼以为只是一个简单的序列型DP问题,于是快速的写下了下面的代码。

技术分享
#include <iostream>
using namespace std;
 
/*
 看着只是简单的序列DP..不知道有没有坑
 DP[k]表示的是有前k个活动可以选择时的答案
 */
 
struct state
{
    int health;//体力 永远大于0
    int wisdom;//智力 最后大于70
    int product;//乘积
    void calc(){
        product = health * wisdom;
    }
    
};
 
struct act
{
    int dh;
    int dw;
};
 
state dp[400+5];
act acts[400+5];
int n;//一共的活动数目
 
void init(){
    cin>>n;
    cin>>dp[0].health>>dp[0].wisdom;
    dp[0].calc();
    for (int i = 1; i <= n; ++i)
    {
        cin>>acts[i].dh>>acts[i].dw;
    }
}
 
void build(){
    for (int i = 1; i <= n; ++i)
    {
        //
        int h = dp[i-1].health + acts[i].dh;
        int w = dp[i-1].wisdom + acts[i].dw;
        
        if( h > 0 ){
            if( h * w >= dp[i-1].product){
                dp[i].health = h;
                dp[i].wisdom = w;
                dp[i].calc();
            }else{
                dp[i] = dp[i-1];
            }
        }else{
            dp[i] = dp[i-1];
        }
    }
    if(dp[n].wisdom > 70 and dp[n].health > 0)
        cout<<dp[n].product<<endl;
    else
        cout<<"Death"<<endl;
}
int main(int argc, char const *argv[])
{
    init();
    build();
    return 0;
}
View Code

这个代码在是求和的时候是可以的,因为前面和最大的情况,+dh +dw仍然也是最大的。

但是在成绩的时候就不然了,例子不好举。但是很明显 当达到积最大有两种情况时,这两种选哪个作为dp值在不知道下一个活动时是无法确定的。

所以就想到,确定一个变量,让一维的DP化为二维。

dp[i][j]表示在前i个活动可以选择时,体力值为j时,最大的智力值是多少。

所以

dp[i][j] =
max {(dp[i-1][j-acts[i].h] + acts[i].w) //选上, (dp[i-1][j]) //不选}
                       

这里有一个细节要注意就是,初始状态是1000,那么数组第二维要开到32000+50才行。(。。最后才发现是这个地方错了 还不报RE真是可恶。。)

还有一个非常重要的细节就是 智力值在过程中是可以为负数的,所以我们初始化时要把智力值全部设置为-INF才可以,这样我们就可以根据智力值与-INF的关系知道当前处理的状态的是经过一系列过程转化来的智力值,还是根本没有办法达到的智力值。(此处也可以在搞一个bool型的二维数组来记录这两种状态,也不麻烦而且更美观)

 

另外还有一个地方可以优化 就是内层循环的次数,我们可以采取迭代递增的方式,让curMax始终是当前可能的最大的体力值,但是实际上没什么太大的效果。

struct act
{
    int dh;
    int dw;
};
 
// state dp[400+5];
int dp[400+5][32000+50]={0};
act acts[500+5];
int n;//一共的活动数目
 
void init(){
    cin>>n;
    for (int i = 0; i <= n; ++i)
    {
        cin>>acts[i].dh>>acts[i].dw;
    }//注意acts[0]存储的是初始情况
    
}
 
void build(){
    //初始化为负无穷 以来判断智力值是转化来的 还是根本没有被利用
    memset(dp,-50000,sizeof(dp));
    
    dp[0][acts[0].dh] = acts[0].dw;//初始化
    int curMax = 31000+50;//固定的curMax 注意31000 = 30000+1000 

    for (int i = 1; i <= n; ++i)
    {
        for (int j = 0; j <= curMax; ++j)
        {

            if(j >= acts[i].dh and dp[i-1][j-acts[i].dh] > -50000){
                //体力值大于0 且 智力值是有效的
                dp[i][j] = max(dp[i-1][j], dp[i-1][j-acts[i].dh]+acts[i].dw);
            }
            else
                dp[i][j] = dp[i-1][j];
        }
    }
    int res = 0; 
    //找到最大的
    for (int j = 1; j <= curMax; ++j)
    {
        if(dp[n][j] > 70){ 
            res = max(res,dp[n][j] * j);
        }
    }
    if(res)
        cout<<res<<endl;
    else
        cout<<"Death"<<endl;
}
 
int main(int argc, char const *argv[])
{
    init();
    build();
    return 0;
}

 

【算法学习笔记】71.动态规划 双重条件 SJTU OJ 1124 我把助教团的平均智商拉低了

标签:

原文地址:http://www.cnblogs.com/yuchenlin/p/sjtu_oj_1124.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!