礼物(贪心,枚举,二分)

题意

农夫约翰想给他的 \(N\) 头奶牛购买礼物,但是他的预算只有 \(B\) 元。

奶牛 \(i\) 希望获得的礼物的价格为 \(P_i\),运输成本为 \(S_i\),也就是说约翰要帮奶牛 \(i\) 买礼物,共需花费 \(P_i+S_i\) 元钱。

约翰有一张特殊的优惠券,如果使用该优惠券来订购一份礼物,那么该礼物的价格会变为只有正常价格的一半。

如果约翰用该优惠券给奶牛 \(i\) 买礼物,那么他只需要支付 \(P_i/2+S_i\) 元钱。

方便起见,\(P_i\) 一定是偶数。

请帮助约翰确定他最多可以给多少头奶牛购买礼物。

数据范围

\(1 \leq N \leq 1000\)

思路

  • 法一:枚举
    先按照不优惠的价格,对牛升序排列。然后枚举对哪头牛使用优惠券即可。

  • 法二:二分
    先按照不优惠的价格,对牛升序排列。二分查找可以买多少头牛,假设当前查找到的值为\(x\)。这时有两种策略:

  1. 对于前\(x\)头牛,可以全选,对其中\(p\)最大的牛使用优惠券。
  2. 选择前\(x - 1\)头牛,然后将优惠券用到\(x \sim n\)\(p/2+s\)最小的牛。
    这两种策略中最小值如果不超过\(B\),则可以买到\(x\)头牛。

代码

  • 枚举
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1010;

int n, m;

struct Cow
{
    int p, s;
    int total;
    
    bool operator < (const Cow &t) const
    {
        return total < t.total;
    }
}cow[N];

int main()
{
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i ++) {
        int p, s;
        scanf("%d%d", &p, &s);
        cow[i] = {p, s, p + s};
    }
    int ans = 0;
    sort(cow + 1, cow + n + 1);
    for(int i = 1; i <= n; i ++) {
        int t = cow[i].p / 2 + cow[i].s;
        if(t > m) continue;
        int num = 1;
        for(int j = 1; j <= n; j ++) {
            if(j == i) continue;
            if(t + cow[j].total > m) break;
            t += cow[j].total;
            num ++;
        }
        ans = max(num, ans);
    }
    printf("%d\n", ans);
    return 0;
}
  • 二分
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long ll;

const int N = 1010;

int n, m;

struct Cow
{
    int p, s;
    int total;
    
    bool operator < (const Cow &t) const
    {
        return total < t.total;
    }
}cow[N];

bool check(int x)
{
    int mx = 0, mi = 2e9;
    for(int i = 1; i <= n; i ++) {
        if(i <= x) mx = max(mx, cow[i].p / 2);
        else mi = min(mi, cow[i].p / 2 + cow[i].s);
    }
    ll sum = 0;
    for(int i = 1; i <= x; i ++) sum += cow[i].total;
    if(sum - mx <= m) return true;
    if(sum - cow[x].total + mi <= m) return true;
    return false;
}

int main()
{
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i ++) {
        int p, s;
        scanf("%d%d", &p, &s);
        cow[i] = {p, s, p + s};
    }
    sort(cow + 1, cow + n + 1);
    int l = 0, r = n;
    while(l < r) {
        int mid = l + r + 1 >> 1;
        if(check(mid)) l = mid;
        else r = mid - 1;
    }
    printf("%d\n", l);
    return 0;
}
posted @ 2022-05-04 11:24  pbc的成长之路  阅读(58)  评论(0)    收藏  举报