一,在求最优解问题的过程中,依据某种贪心标准,从问题的初始状态出发,直接去求每一步的最优解,通过若干次的贪心选择,最终得出整个问题的最优解,这种求解方法就是贪心算法。
通过对每一步选取局部最优解进而得出整个问题的最优解。
二,利用贪心策略解题,需要解决两个问题:
1该题是否适合于用贪心策略求解;
2如何选择贪心标准,以得到问题的最优/较优解。
贪心的性质
贪心选择性质 是指所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到。
具有最优子结构 当一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质。
运用贪心策略在每一次转化时都取得了最优解(且必须需具备无后效性,当前状态不会影响以后状态)。问题的最优子结构性质是该问题可用贪心算法或动态规划算法求解的关键特征。
贪心算法的每一次操作都对结果产生直接影响。
贪心算法对每个子问题的解决方案都做出选择,不能回退。
三,使用贪心算法求解问题应该考虑如下几个方面:
(1)候选集合A:为了构造问题的解决方案,有一个候选集合A作为问题的可能解,即问题的最终解均取自于候选集合A。
(2)解集合S:随着贪心选择的进行,解集合S不断扩展,直到构成满足问题的完整解。
(3)解决函数solution:检查解集合S是否构成问题的完整解。
(4)选择函数select:即贪心策略,这是贪心法的关键,它指出哪个候选对象最有希望构成问题的解,选择函数通常和目标函数有关。
(5)可行函数feasible:检查解集合中加入一个候选对象是否可行,即解集合扩展后是否满足约束条件。
四,例题
1背包问题
给定一个载重量为M的背包,考虑n个物品,其中第i个物品的重量 ,价值wi (1≤i≤n),要求把物品装满背包,且使背包内的物品价值最大。
有两类背包问题(根据物品是否可以分割),如果物品不可以分割,称为0—1背包问题(动态规划);如果物品可以分割,则称为背包问题(贪心算法)。
可分割类 根据性价比放入背包先放最大性价比
直到背包内的空间不足以放进下一个完整的物品由于物品是可以分割的所以将这个物品放入部分就可以得到最优解。
2最优装载问题
有一批集装箱要装上一艘载重量为c的轮船,其中集装箱i的重量为wi。最优装载问题要求确定在装载体积不受限制的情况下,将尽可能多的集装箱装上轮船。
采用重量最轻者先装的贪心选择策略,可得到装载问题的最优解。
3多处最优服务次序
设有n个顾客同时等待一项服务,顾客i需要的服务时间为ti,1≤i≤n,共有s处可以提供此项服务。应如何安排n个顾客的服务次序才能使平均等待时间达到最小?
时间短的人在前可以让所有顾客的等待时间变少因此只需要按耗费时间的顺序来计算所有人的等待时间即可 注意平均等待时间是n个顾客等待时间的总和除以n并不是等待时间最长的顾客除以n
4搬桌子问题
这层楼沿着走廊南北向的两边各有200个房间。最近,公司要做一次装修,需要在各个办公室之间搬运办公桌。
由于走廊狭窄,办公桌都很大,走廊里一次只能通过一张办公桌。必须制定计划提高搬运效率。
经理制定如下计划:一张办公桌从一个房间移到另一个房间最多用十分钟。当从房间i移动一张办公桌到房间j,两个办公室之间的走廊都会被占用。所以,每10分钟内,只要不是同一段走廊,都可以在房间之间移动办公桌。
可以将每次搬桌子时经过那些房间记录下来如有重复经过那边是不能同时搬桌子的只能分开办。因此被经过最多的房间的次数就是最少要办的次数。
5钓鱼
约翰有h(1≤h≤16)个小时的时间,在该地区有n(2≤n≤25)个湖,这些湖刚好分布在一条路线上,该路线是单向的。约翰从湖1出发,他可以在任一个湖结束钓鱼。但他只能从一个湖到达另一个与之相邻的湖,而且不必每个湖都停留。
假设湖i(i=1~n—1),以5分钟为单位,从湖i到湖i+1需要的时间用ti(0<ti≤192)表示。例如t3=4,是指从湖3到湖4需要花20分钟时间。
已知在最初5分钟,湖i预计钓到鱼的数量为fi(fi≥0)。以后每隔5分钟,预计钓到鱼的数量将以常数di(di≥0)递减。如果某个时段预计钓到鱼的数量小于或等于di,那么在下一时段将钓不到鱼。为简单起见,假设没有其它的钓鱼者影响约翰的钓鱼数量。
由于他可以在任意一个湖终止钓鱼因此需要遍历从每个湖终止的时候所能钓到的最多的鱼,最后在选出能钓的最多的鱼是多少。首先将走路的时间去掉剩下净钓鱼时间并把净钓鱼时间按次划分每五分钟一次)由于在任何时候鱼的数目只和约翰在该湖里钓鱼的次数有关,和钓鱼的总次数无关,所以这个策略是最优的。一共可以钓鱼time次,每次在n个湖中选择鱼最多的一个湖钓鱼。
最重要的是当 第一次在一号湖第二次在二号湖第三次在一号湖和前两次在一号湖第三次在二号湖的效果是一样的。
#include <iostream>
#include <queue>
using namespace std;
struct data {
int f,d,id;
}a[30],b;
int n,t,tran[30],x,ans,maxi,save[30],tmp[30],tt;
priority_queue <data> q;
bool operator<(data a,data b) {
if (a.f==b.f) return a.id>b.id;
else return a.f<b.f;
}
int main() {
while (~scanf("%d",&n)) {
if (n==0) break;
scanf("%d",&t);
t *= 12;
for (int i=1;i<=n;i++)
scanf("%d",&a[i].f);
for (int i=1;i<=n;i++) {
scanf("%d",&a[i].d);
a[i].id = i;
}
tran[1] = 0;
for (int i=2;i<=n;i++) {
scanf("%d",&x);
tran[i] = tran[i-1] + x;
}
ans = -1;
memset(save,0,sizeof(save));
for (int i=1;i<=n;i++) {
maxi = 0;
memset(tmp,0,sizeof(tmp));
tt = t - tran[i];
while (!q.empty()) q.pop();
for (int j=1;j<=i;j++)
q.push(a[j]);
while (tt>0) {
b = q.top();
q.pop();
tt--;
maxi += b.f;
tmp[b.id]++;
b.f -= b.d;
if (b.f<=0) b.f = 0;
q.push(b);
}
if (maxi>ans) {
ans = maxi;
for (int j=1;j<=i;j++)
save[j] = tmp[j];
}
}
for (int i=1;i<n;i++)
printf("%d, ",save[i]*5);
printf("%d\n",save[n]*5);
printf("Number of fish expected: %d\n\n",ans);
}
return 0;
}