贪心算法专题总结

一、贪心算法意义
贪心算法是指在对问题求解时,总是做出在当前看来是最好的选择。不是从整体最优加以考虑,他做出的仅仅是在某种意义上的局部最优解。过若干次的贪心选择,最终得出整个问题的最优解,这种求解方法就是贪心算法。
二、贪心算法的理论基础
贪心算法是一种在每一步选择中都采取在当前状态下最好或最优的选择,以找出整体最优解。贪心算法的每一次操作都对结果产生直接影响。贪心算法对许多问题它能产生整体最优解,但不能保证总是有效,因为它不是对所有问题都能得到整体最优解。
一次循环可以找出结果:如果是一重循环,运算n次找出结果;如果是二重循环,运算n*n次找出结果。
三、贪心算法求解过程
1.候选集合A:为了构造问题的解决方案,有一个候选集合A作为问题的可能解。
2.解集合S:随着贪心选择的进行,解集合S不断扩展,直到构成满足问题的完整解。
3.解决函数solution:检查解集合S是否构成问题的完整解。
4.选择函数select:即贪心策略,这是贪心法的关键,它指出哪个候选对象最有希望构成问题的解,选择函数通常和目标函数有关。
5.可行函数feasible:检查解集合中加入一个候选对象是否可行,即解集合扩展后是否满足约束条件。
四、贪心算法典型例题
1.贪心算法:
题目:
给定一个载重量为M的背包,考虑n个物品,其中第i个物品的重量 ,价值wi (1≤i≤n),要求把物品装满背包,且使背包内的物品价值最大。
有两类背包问题(根据物品是否可以分割),如果物品不可以分割,称为0—1背包问题(动态规划);如果物品可以分割,则称为背包问题(贪心算法)。
方法:
(1)当作0—1背包问题,用动态规划算法;
(2)当作0—1背包问题,用贪心算法,按性价比从高到底顺序选取物品。物品不可分割时,可能剩下空间会被浪费。
(3)当作背包问题,用贪心算法,按性价比从高到底的顺序选取物品。物品可以分割时,剩下的空间装入剩下物品性价比最高的一部分。
2.排队打水问题:
题目:
有n个人去排队打水,一共有m个水龙头,每个人打水时间分别是t1,t2,…,tn,怎样排队打水怎样能使总排队时间最短?
方法:
T1=t1;
T2=t1+t2;
T3=t1+t2+t3;

Tn=t1+t2+t3+…+tn;
所以,打水时间少的的人先打可以让总排队时间最少,使用sort排序将所有人的打水时间从大到小排序,从前往后按顺序大水即可。
五、上课讲的最难的一道题!(钓鱼问题分析
题目:
约翰有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,那么在下一时段将钓不到鱼。为简单起见,假设没有其它的钓鱼者影响约翰的钓鱼数量。
编写程序,帮助约翰制定钓鱼旅行的计划,以便尽可能多的钓到鱼。
应该注意的点:钓鱼路线只能是单向的;从一个湖到另一个湖需要一定的实时间;一个湖预计钓到鱼的数量按一定的函数随时间降低;一个湖正在钓鱼不会影响其他的湖钓到鱼的数量;一个湖可以钓多次鱼。
方法:假设在第m个湖,停止,除去走路的时间剩下的式净钓鱼的时间。每次都从预计能钓到鱼的数量最大的湖钓鱼直到小于第二名为止;然后再次对所有的湖排序,选取最大的钓,因为已经去掉了走路时间,所以可以折回来,等价于正向前进时就已经钓过了。至于在那个湖停止钓鱼,使用枚举算法求最优解。
代码(非自己写,上课讲的):

#include <bits/stdc++.h>
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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值