1 理论知识
📢 贪心算法是一种在每一步选择中都采取在当前状态下最好或者最优的选择,从而希望得到最好或者最优结果的算法。它对一些问题都能产生整体最优解,但并不能保证总是有效,只能说其解必然是最优解的很好的近似值。
-
💥 贪心选择性质
是指所求问题的整体最优解可以通过一系列局部最优的选择来获得。对每个问题,要确定其是否具有贪心选择性质,必须证明每一步所做的贪心选择最终会导致问题的整体最优解。 -
💥最优子结构性质
是指一个的最优解包含其子问题的最优解。贪心算法的每一次操作都会对结果产生直接影响,而动态规划则不会。贪心算法对每个子问题的解决方案都做出选择,不能回退;而动态规划则会根据以前的选择结果对当前进行选择,有回退功能。
2 求解步骤
📢 相关概念:
- 1️⃣ 候选集合Candidate:为问题的可能解,即问题的最终解均来自于该候选集合;
- 2️⃣ 解集合Answer:为最终求解的完整解;
- 3️⃣ 解决函数Solution:检验解集合是否已经构成该问题的完整解;
- 4️⃣ 选择函数Select:贪心策略;
- 5️⃣ 可行函数Feasible:检验解集合中新加入的候选对象是否可行。
📢 一般流程的伪代码:
Greedy(Candidate)
{
Answer={};
while(!Solution(Answer))//未构成完整解
{
object=Select(Candidate);
if(Feasible(Answer,object)==true)
{
Answer=Answer+{object};
Candidate=Candidate-{object};
}
}
return Answer;
}
3 实例分析
✨ 问题描述:现给定所有种类月饼的库存量、总售价及市场的最大需求量,计算可以获取的最大收益。
👉 输入:每个输入包含一个测试用例。第一行:N(月饼的种类数),D(市场的最大需求量)。第二行:N个正数,表示每种月饼的库存量。第三行:N个正数,表示每种月饼的总售价。数字间以空格隔开。
🎈 策略:总是选择单价最高的月饼出售(贪心思想),即可获取最大的利益。
3.1 源代码
#include <stdio.h>
#include <algorithm>
using namespace std;
struct mooncake
{
double store; // 库存量
double total_price; // 总售价
double price; //单价
int flag; //月饼类型,依照出现顺序,依次定义为0,1,2……
}cake[1001];
bool cmp(mooncake m1, mooncake m2)
{//排序
return m1.price > m2.price;
}
int main()
{
int N, i; //N表示月饼的种类数
double D,res=0; //D表示市场最大需求量,res表示收益
scanf_s("%d%lf", &N, &D);
for (i = 0; i < N; i++)
{
scanf_s("%lf", &cake[i].store);
}
for (i = 0; i < N; i++)
{
scanf_s("%lf", &cake[i].total_price);
cake[i].flag = i;
cake[i].price = cake[i].total_price / cake[i].store;
}
sort(cake, cake + N, cmp);
for (i = 0; i < N; i++)
{
if (cake[i].store <= D)//需求量不小于此种月饼库存量
{
D -= cake[i].store;//此种月饼全部卖出
res += cake[i].total_price;
printf("第%d种月饼,售出量为:%.2f\n", cake[i].flag, cake[i].store);
}
else//需求量小于此种月饼库存量
{
res += cake[i].price*D;//此种月饼按需卖出
printf("第%d种月饼,售出量为:%.2f\n", cake[i].flag, D);
break;
}
}
printf("总收益为:%.2f\n", res);
return 0;
}