前言
接着第四章
本篇总结自《算法笔记》4.4 贪心
正文
知识点1:简单贪心
贪心是只考虑当下的一种局部最优(或较优),来使全局结果达到最优(或较优)的策略。
证明策略是最优(或较优)的:反证法、数学归纳法【证明较复杂,若有不错的思路且无法找到反例,直接实现即可】
例1 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 ", ans); return 0; }
只在乎销售额,只要每次选最贵的就能达到总销售额最多(贪心)。
例2 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; }
只要每次都拿最小的数放在最高位,最后组成的数必然最小(贪心)。
知识点2:区间贪心(给出若干小区间,看最多能塞多少个)
#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 ", ans); } return 0; }
稍微复杂的贪心策略:如下图两种情况按下标顺序选取