HDU 3236

今天比赛又血崩,一道弱智题硬生生写成了模拟,最后超时。。昨天那道kmp+dp依旧是没做出来。。

今天比赛上的I题,一直没做出来,自己还是很烂啊,一道很水的dp吧,大神都秒A,我这个渣渣整场比赛硬是没做出来。

这道题卡的内存,因为状态转移时,只需要记录前一个状态就行根本不需要全部都记录。。涨姿势了。

题意虐狗:你有v1,v2的钱,必须分开使用,给女朋友买礼物,其中有一些礼物女朋友必须要,如果当前的钱买不了所有女朋友想要的,那么就输出-1;否则输出女朋友最大的开心程度。。。(女朋友的心情用数据衡量,程序员还是有意思哈。。。)

思路:i为当前已经使用v1的金钱,j为当前已经使用v2的金钱,k为当前走到第几个物品,l为是否用掉免费机会。对于女朋友必要的物品,必须全买,因此没有不买这一说,而对于不必要的物品,可以买,也可以不买。

四种状态转移:用v1买,dp[k + 1][i + p][j][l] = max(dp[k + 1][i + p][j][l], dp[k][i][j][l] + h);用v2买,dp[k + 1][i][j + p][l] = max(dp[k + 1][i][j + p][l], dp[k][i][j][l] + h);k>=m时,可以不买即,dp[k + 1][i][j][l] = max(dp[k][i][j][l], dp[k + 1][i][j][l]);还有当l==0时,使用免费机会dp[k + 1][i][j][l + 1] = max(dp[k + 1][i][j][l + 1], dp[k][i][j][l] + h)。还有特别要注意的一点是,当k>=m时,在状态转移时,要判当前状态合不合法,即dp[k][i][j][l] >= sum,否则结果会将没有买全女朋友必要的物品的也算进去,这样结果就不正确了,查这个问题查了好久。。。

下面附代码,只是把上述的k变成0和1两种状态,以减少空间的使用,不然会MLE。。。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int dp[2][501][51][2];
struct Gift
{
    int p, h, s;

}a[301];

int v1, v2, n, m;
int kase = 0;
int sum;
const int INF = 0x7fffffff;
bool cmp(const Gift &t1, const Gift &t2)
{
    return t1.s > t2.s;
}
void DP(int m, int n, int flag)
{
    memset(dp, 0, sizeof(dp));
    for(int k = 0; k < n; ++k)
    {
        int p = a[k].p;
        int h = a[k].h;
        memset(dp[1 - k % 2], 0, sizeof(dp[1 - k % 2]));
        for(int i = 0; i <= v1; ++i)
        {
            for(int j = 0; j <= v2; ++j)
            {

                for(int l = 0; l < 2; ++l)
                {
                    if(k >= m)
                    {
                        if(flag && dp[k % 2][i][j][l] < sum)
                            continue;
                        dp[1 - k % 2][i][j][l] = max(dp[k % 2][i][j][l], dp[1 - k % 2][i][j][l]);
                    }
                    if(i + p <= v1)
                        dp[1 - k % 2][i + p][j][l] = max(dp[1 - k % 2][i + p][j][l], dp[k % 2][i][j][l] + h);
                    if(j + p <= v2)
                        dp[1 - k % 2][i][j + p][l] = max(dp[1 - k % 2][i][j + p][l], dp[k % 2][i][j][l] + h);
                    if(l == 0)
                        dp[1 - k % 2][i][j][l + 1] = max(dp[1 - k % 2][i][j][l + 1], dp[k % 2][i][j][l] + h);
                }
            }
        }
    }
}
int main()
{
    while(~scanf("%d%d%d", &v1, &v2, &n) && (v1 || v2 || n))
    {
        for(int i = 0; i < n; ++i)
        {
            scanf("%d%d%d", &a[i].p, &a[i].h, &a[i].s);
        }
        sort(a, a + n, cmp);
        m = n;
        sum = 0;
        for(int i = 0; i < n; ++i)
        {
            if(a[i].s == 0)
            {
                m = i;
                break;
            }
            sum += a[i].h;
        }
        DP(0, m, 0);
        if(dp[m % 2][v1][v2][1] < sum)
        {
            printf("Case %d: -1\n\n", ++kase);
        }
        else
        {
            DP(m, n, 1);
            printf("Case %d: %d\n\n", ++kase, dp[n % 2][v1][v2][1]);
        }
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值