贪心

贪心是只考虑当下的一种局部最优(或较优),来使全局结果达到最优(或较优)的策略。
证明策略是最优(或较优)的:反证法、数学归纳法【证明较复杂,若有不错的思路且无法找到反例,直接实现即可】

简单贪心

🌰 PAT B1020(卖月饼P118)
📣 只在乎销售额,只要每次选最贵的就能达到总销售额最多(贪心)。

#include<cstdio>
#include<algorithm>
using namespace std;

struct mooncake { // 结构体整合输入数据
    double store; // 库存
    double sell; // 总价
    double price; // 单价(库存除总价)
}cake[1010];

bool cmp(mooncake a, mooncake b) {
    return a.price > b.price;
}

int main() {
    int n; // 月饼种类数
    double D; // 月饼需求量
    scanf("%d%lf", &n, &D);
    for(int i = 0; i < n; i++) { // 输入库存
        scanf("%lf", &cake[i].store);
    }
    for(int i = 0; i < n; i++) { // 输入总价 并计算单价
        scanf("%lf", &cake[i].sell);
        cake[i].price = cake[i].sell / cake[i].store;
    }
    sort(cake, cake + n, cmp); // 按单价从高到低排序
    double ans = 0; // 收益
    for(int i = 0; i < n; i++) { // 遍历排序后的月饼列表cake
        if(D >= cake[i].store) { // 需求大于供应
            D -= cake[i].store;
            ans += cake[i].sell; // 该类月饼全部卖出
        } else { // 需求小于供应
            ans += cake[i].price * D; // 需求全部满足
            break;
        }
    }
    printf("%.2f\n", ans);
    return 0;
}

🌰 PAT B1023(组个最小数)
📣 只要每次都拿最小的数放在最高位,最后组成的数必然最小(贪心)。

#include<cstdio>

int main() {
    int count[10]; // 记录数字0~9的个数
    for(int i = 0; i < 10; i++) {
        scanf("%d", count + i); // 录入0~9各数字个数
    }
    for(int i = 1; i < 10; i++) {
        if(count[i] > 0) {
            printf("%d", i); // 输出除0外最小的数作为最高位
            count[i]--;
            break;
        }
    }
    for(int i = 0; i < 10; i++) {
        for(int j = 0; j < count[i]; j++) { // 把i输出count[i]次
            printf("%d", i);
        }
    }
    return 0;
}

区间贪心

给出若干小区间,看最多能塞多少个

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 110;
struct Interval{
    int x, y;
}I[maxn];

bool cmp(Interval a, Interval b) {
    if(a.x != b.x) return a.x > b.x; // 左端点从大到小
    else return a.y < b.y; // 左端点相同时,右端点从小到大(写b.y > a.y容易理解错)
}

int main() {
    int n;
    while(scanf("%d", &n), n != 0) { // 输入提供选择的区间个数
        for (int i = 0; i < n; i++)
        {
            scanf("%d%d", &I[i].x, &I[i].y); // 顺序输入区间的左右端点
        }
        sort(I, I + n, cmp); // 把区间排序
        int ans = 1, lastX = I[0].x; // ans记录不相交区间数,lastX记录上一个被选区间的左端点
        for(int i = 1; i < n; i++) {
            if(I[i].y <= lastX) { // 若该区间右端点在lastX左边
                lastX = I[i].x; // 以I[i]作为新选中的区间
                ans++; // 区间数++
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}

稍微复杂的贪心策略

alt 区间不相交的问题