P3985 不开心的金明

P3985 不开心的金明

题目描述

金明今天很不开心,家里购置的二手房就要领钥匙了,房里并没有一间他自己专用的很宽敞的房间。更让他不高兴的是,妈妈昨天对他说:“你需要购买哪些物品,怎么布置,你说了不算(有很大的限制),而且不超过W元钱。”。今天一早金明就开始做预算,但是他想买的东西太多了,肯定会超过妈妈限定的W元。于是,他把每件物品规定了一个重要度整数pi表示。他还从因特网上查到了每件物品的价格vi(都是整数元)。

妈妈看到购物单后进行了审查,要求购物单上所有的物品价格的极差(最贵的减去最便宜的)不超过3(当然金明至今不知道为什么会这样)。他希望在不超过W元(可以等于W元)的前提下,使购买的重要度总和∑pi的最大。

请你帮助金明设计一个满足要求的购物单,你只需要告诉我们重要度的最大的和。

输入格式

输入的第1行,为两个正整数,用一个空格隔开:

n W (其中W表示总钱数,n为希望购买物品的个数。)

从第2行到第n+1行,第j行给出了编号为j-1的物品的基本数据,每行有2个非负整数v p (其中v表示该物品的价格,p表示该物品的重要度)

输出格式

输出只有一个正整数,为不超过总钱数的物品的重要度的总和的最大值

输入样例

5 10
2 800
5 400
5 300
3 400
2 200

输出样例

1600

数据范围

1 ≤ N ≤ 100

1 ≤ W ≤ 1e9

1 ≤ vi ≤ 1e9

对所有的i=1,2,3,…,N,min(vi) ≤ vi ≤min(vi) + 3

1 ≤ pi ≤ 1e7

解题思路

这里有几个比较重要的条件需要先明确一下对所有的i=1,2,3,…,N,min(vi) ≤ vi ≤min(vi) + 3这个条件说明了只有四种状态的价格存在,即为0 1 2 3。极差是3,最多购买件数为100,所以这里买全都买最便宜的和全都买最贵的物品的价格相差就是 3 * 100 = 300。

300是蛮重要的一个点,我们想如果最便宜的物品的价格超过300,假设最便宜的是301,则最贵的价格就为304,那么我们全都买最贵的和全都买最便宜的价格分别是 30100和30400, 价格相差了300,这300即买不了最便宜的物品更买不了最贵的物品,所以最便宜的物品价格一旦超过了300,此时我们就可以用贪心来做,而最小值没有超过300时我们就可以用01背包来做。

还有一个点就是题目中说到n件物品的价格之和 >= w,那么超过300后的购买件数就为w/minn_val或者 w/maxx_val都可以。

参考代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e7 + 7;
const int inf = 2147483647;
const double PI = acos(-1.0);
int val[maxn], pi[maxn];
ll dp[maxn] = {0};
int main()
{
    int n, w, maxx_val = 0, minn_val = inf;
    scanf("%d %d", &n, &w);
    for (int i = 1; i <= n; i++)
    {
        scanf("%d %d", &val[i], &pi[i]);
        maxx_val = max(maxx_val, val[i]);
        minn_val = min(minn_val, val[i]);
    }
    if (minn_val <= 300)
    {
        for (int i = 1; i <= n; i++)
            for (int j = w; j >= val[i]; j--)
                dp[j] = max(dp[j], dp[j - val[i]] + pi[i]);
        printf("%lld\n", dp[w]);
    }
    else
    {
        ll sum = 0;
        sort(pi + 1, pi + n + 1);
        for (int i = 1; i <= w / maxx_val; i++)
            sum += pi[n - i + 1];
        printf("%lld", sum);
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TUStarry

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值