Skip to content

16 、贪心


1、思想📌

Tip

把一个问题分成若干个小问题,找局部最优解


例题📌

e.g.32【深基12.例1】部分背包问题📌

题目描述

阿里巴巴走进了装满宝藏的藏宝洞。藏宝洞里面有 \(N(N \le 100)\) 堆金币,第 \(i\) 堆金币的总重量和总价值分别是 \(m_i,v_i(1\le m_i,v_i \le 100)\)。阿里巴巴有一个承重量为 \(T(T \le 1000)\) 的背包,但并不一定有办法将全部的金币都装进去。他想装走尽可能多价值的金币。所有金币都可以随意分割,分割完的金币重量价值比(也就是单位价格)不变。请问阿里巴巴最多可以拿走多少价值的金币?

输入格式

第一行两个整数 \(N,T\)

接下来 \(N\) 行,每行两个整数 \(m_i,v_i\)

输出格式

一个实数表示答案,输出两位小数

样例

样例输入

1
2
3
4
5
4 50
10 60
20 100
30 120
15 45

样例输出

240.00
#include <bits/stdc++.h>
using namespace std;
struct node {
    int weight;
    int value;
    double avg;
} e[100005];

bool cmp(node a, node b) {
    return a.avg > b.avg;
}

int main() {
    int n, t;
    cin >> n >> t;
    for (int i = 1; i <= n; i++) {
        cin >> e[i].weight >> e[i].value;
        e[i].avg = (double)e[i].value / e[i].weight;
    }
    sort(e + 1, e + n + 1, cmp);
    double ans = 0;
    for (int i = 1; i <= n; i++) {
        if (t >= e[i].weight) {
            ans += e[i].value;
            t -= e[i].weight;
        } else {
            ans += e[i].avg * t;
            t = 0;
            break;
        }
    }
    printf("%.2lf\n", ans);
}

e.g.33 凌乱的yyy / 线段覆盖📌

题目背景

快 noip 了,yyy 很紧张!

题目描述

现在各大 oj 上有 \(n\) 个比赛,每个比赛的开始、结束的时间点是知道的。

yyy 认为,参加越多的比赛,noip 就能考的越好(假的)。

所以,他想知道他最多能参加几个比赛。

由于 yyy 是蒟蒻,如果要参加一个比赛必须善始善终,而且不能同时参加 \(2\) 个及以上的比赛。

输入格式

第一行是一个整数 \(n\),接下来 \(n\) 行每行是 \(2\) 个整数 \(a_{i},b_{i}\ (a_{i}<b_{i})\),表示比赛开始、结束的时间。

输出格式

一个整数最多参加的比赛数目。

样例

样例输入

1
2
3
4
3
0 2
2 4
1 3

样例输出

2

提示

  • 对于 \(20\%\) 的数据,\(n \le 10\)
  • 对于 \(50\%\) 的数据,\(n \le 10^3\)
  • 对于 \(70\%\) 的数据,\(n \le 10^{5}\)
  • 对于 \(100\%\) 的数据,\(1\le n \le 10^{6}\)\(0 \le a_{i} < b_{i} \le 10^6\)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6;
struct node
{
    ll l,r;
}e[N];
ll n;
bool cmp(node n1,node n2)
{
    return n1.r<n2.r;
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++) cin>>e[i].l>>e[i].r;
    sort(e+1,e+1+n,cmp);
    int ans=0,t=0;
    for(int i=1;i<=n;i++)
    {
        if(t<=e[i].l)
        ans++,t=e[i].r;
    }
    cout<<ans<<endl;
    return 0;
}

e.g.34 [USACO05NOV] 奶牛玩杂技📌

题目背景

Farmer John 养了 \(N\) 头牛,她们已经按 \(1\sim N\) 依次编上了号。FJ 所不知道的是,他的所有牛都梦想着从农场逃走,去参加马戏团的演出。可奶牛们很快发现她们那笨拙的蹄子根本无法在钢丝或晃动的的秋千上站稳(她们还尝试过把自己装在大炮里发射出去,但可想而知,结果是悲惨的) 。最终,她们决定练习一种最简单的杂技:把所有牛都摞在一起, 比如说, 第一头牛站在第二头的身上, 同时第二头牛又站在第三头牛的身上...最底下的是第 \(N\) 头牛。

题目描述

每头牛都有自己的体重以及力量,编号为 \(i\) 的奶牛的体重为 \(W_i\),力量为 \(S_i\)

当某头牛身上站着另一些牛时它就会在一定程度上被压扁,我们不妨把它被压扁的程度叫做它的压扁指数。对于任意的牛,她的压扁指数等于摞在她上面的所有奶牛的总重(当然不包括她自己)减去它的力量。奶牛们按照一定的顺序摞在一起后, 她们的总压扁指数就是被压得最扁的那头奶牛的压扁指数。

你的任务就是帮助奶牛们找出一个摞在一起的顺序,使得总压扁指数最小。

输入格式

第一行一个整数 \(N\)

接下来 \(N\) 行,每行两个整数 \(W_i\)\(S_i\)

输出格式

一行一个整数表示最小总压扁指数。

样例

样例输入

1
2
3
4
3
10 3
2 5
3 3

样例输出

2

提示

对于 \(100\%\) 的数据,\(1 \le N \le 5\times 10^4\)\(1 \le W_i \le 10^4\),$