P3985 不开心的金明 - 洛谷
题意
金明今天很不开心,家里购置的二手房就要领钥匙了,房里并没有一间他自己专用的很宽敞的房间。更让他不高兴的是,妈妈昨天对他说:“你需要购买哪些物品,怎么布置,你说了不算(有很大的限制),而且不超过 W 元钱。”。今天一早金明就开始做预算,但是他想买的东西太多了,肯定会超过妈妈限定的 W 元。于是,他把每件物品规定了一个重要度整数 p i p_i pi 表示。他还从因特网上查到了每件物品的价格 v i v_i vi(都是整数元)。
妈妈看到购物单后进行了审查,要求购物单上所有的物品价格的极差(最贵的减去最便宜的)不超过 3(当然金明至今不知道为什么会这样)。他希望在不超过 W 元(可以等于 W 元)的前提下,使购买的重要度总和 ∑ p i \sum p_i ∑pi 的最大。
请你帮助金明设计一个满足要求的购物单,你只需要告诉我们重要度的最大的和。
数据范围
1 ≤ N ≤ 100 1≤N≤100 1≤N≤100
1 ≤ W ≤ 1 0 9 1 \le W \le 10^9 1≤W≤109
1 ≤ v i ≤ 1 0 9 1 \le vi \le 10^9 1≤vi≤109
对所有的 i=1,2,3,…,N, m i n ( v i ) ≤ v i ≤ m i n ( v i ) + 3 min(v_i) \le v_i \le min(v_i)+3 min(vi)≤vi≤min(vi)+3.
1 ≤ p i ≤ 1 0 7 1 \le p_i \le 10^7 1≤pi≤107
思路
从数据范围可以看出如果使用背包的话,会超空间范围。
这时注意题目中的要求 所有物品的极差不超过3 ,这说明当 n 个物品中的最小值超过300时,无需考虑体积的限制,贪心地找重要度最大的物品即可。这是因为,假设我们买了100件物品(最多件),那么都买价值最大的和都买价值最小的物品所花费的总钱数的差值不超过300,但此时所有物品中价值最小的物品的价格超过300,所以无法再买一件产品,这时,只需要贪心地考虑重要度即可。
如果最小值小于300 那么进行01背包即可
代码
#include<bits/stdc++.h>
// #define int long long
#define INF 0x3f3f3f3f
#define mod 1000000007
#define MOD 998244353
#define rep(i, st, ed) for (int (i) = (st); (i) <= (ed);++(i))
#define pre(i, ed, st) for (int (i) = (ed); (i) >= (st);--(i))
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
template<typename T> inline T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template<typename T> inline T lowbit(T x) { return x & -x; }
template<typename T> T qmi(T a, T b = mod - 2, T p = mod) { T res = 1; b %= (p - 1 == 0 ? p : p - 1); while (b) { if (b & 1) { res = (LL)res * a % p; }b >>= 1; a = (LL)a * a % p; }return res % mod; }
const int N = 300 * 101;
int n, w;
int dp[N];
struct Node {
int v, p;
bool operator<(const Node& w)const {
return this->p > w.p;
}
}node[200];
void solve() {
cin >> n >> w;
int minn = INF;
for (int i = 1; i <= n; ++i) {
cin >> node[i].v >> node[i].p;
minn = min(minn, node[i].v);
}
if (minn >= 300) {
sort(node + 1, node + 1 + n);
int sum = 0, res = 0;
for (int i = 1; i <= n; ++i) {
if (sum + node[i].v > w)break;
else {
sum += node[i].v;
res += node[i].p;
}
}
cout << res << endl;
}
else {
int res = 0;
for (int i = 1; i <= n; ++i) {
for (int j = w; j >= node[i].v; --j) {
dp[j] = max(dp[j], dp[j - node[i].v] + node[i].p);
}
}
for (int i = 0; i <= w; ++i) {
res = max(res, dp[i]);
}
cout << res << endl;
}
}
signed main() {
// int T; cin >> T;
// while (T--)
solve();
return 0;
}