买衣服 - 贪心
买衣服
题目描述
小X来到了非主流服装店,他看上了 n 件衣服,每一件衣服价格为 Pi,小X现在手中共有 m 个单位的现金,以及 k 张优惠卷。小X可以在购买某件衣服时,使用至多一张优惠券,若使用优惠券,则该衣服的价格会下降至 Qi,小X想知道他最多可以买几件衣服。
输入格式:
第一行包含三个用空格隔开的正整数 n,k,m,依次表示衣服总数和优惠券数量及现金总数。
接下来 n 行每行包含两个整数 Pi,Qi,表示该件衣服的价格和优惠价。数据保证 Pi>=Qi。
输出格式: 输出数据仅有一行包含一个整数,表示小 X 最多能购买的衣服数。
| 输入样例 | 输出样例 |
|---|---|
4 1 7 3 2 2 2 8 1 4 3 |
3 |
样例解释
一种最优的购买方式是购买1,2,3 号物品,并用优惠券购买物品3,总共花费为3 + 2 + 1 = 6。
数据范围: \(n<=50000,k<=50000,m<=10^{16}\)
思路 选一个合适的贪心策略,但如何证明该策略的正确性?——自行思考,不保证正确。
贪心策略1:将所有衣服优惠前后都加放入堆中,接下来维护一些信息
- 优惠前后的同一件衣服只能买一次
- 剩余现金
- 剩余优惠卷
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 10, INF = 0x3f3f3f3f, MOD = 1E9 + 7;
int n, k, m, ans;
bool st[N];
struct T {
int p, q, i;
bool operator<(const T& r) const { return p > r.p; }
};
priority_queue<T> qu;
int main(int argc, char* argv[]) {
cin >> n >> k >> m;
for (int i = 1, p, q; i <= n; i++)
cin >> p >> q, qu.push({p, q, i}), qu.push({q, -1, i});
while (qu.size()) {
auto u = qu.top(); qu.pop();
if (st[u.i] || m < u.p) continue;
if (u.q == -1 && k == 0) continue;
if (u.q == -1) k--;
m -= u.p, st[u.i] = 1, ans++;
}
cout << ans << endl;
return 0;
}
贪心策略2:先按优惠后价格从小到大排,买完可使用优惠卷的;再按优惠前价格从小到大排,直到买不起下一件为止。如果使用优惠价前后价格相同,那么看作不使用优惠卷。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1E9 + 7;
ll n, k, m, ans;
bool st[N];
struct T {
ll p, q, i;
} a[N];
int P = 1e4;
int main(int argc, char* argv[]) {
cin >> n >> k >> m;
for (int i = 1, p, q; i <= n; i++)
cin >> p >> q, a[i] = {p, q, i}, assert(p < P), assert(q < P);
sort(a + 1, a + 1 + n, [&](T& l, T& r) { return l.q < r.q; });
for (ll i = 1; i <= min(k, n); i++)
if (m >= a[i].q && !st[a[i].i]) {
m -= a[i].q, st[a[i].i] = 1, ans++;
if (a[i].p == a[i].q) k++;
}
sort(a + 1, a + 1 + n, [&](T& l, T& r) { return l.p < r.p; });
for (ll i = 1; i <= n; i++)
if (m >= a[i].p && !st[a[i].i]) {
m -= a[i].p, st[a[i].i] = 1, ans++;
}
cout << ans << endl;
return 0;
}

浙公网安备 33010602011771号