面向问题求解的高级程序设计:(三)贪心算法

13 篇文章 0 订阅

系列文章目录

面向问题求解的高级程序设计:
(一)枚举
(二)查找
(三)贪心算法
(四)搜索
(五)分治与递归
(六)动态规划
(七)最短路
(八)最小生成树
(九)数论
(十)期中回顾



一、贪心算法

  • 贪心,在现实中的意思是“贪得无厌,不知足”,代表一种只顾眼前利益,不顾及长远局面的行为。在一般情况下,“贪心”是个贬义词。
  • 贪心算法,有些教材上又称为贪婪算法,正是采纳了“贪心”中的“只顾眼前”这一点。贪心算法往往用来解决最优化问题,即求在一定约束下的全局最优解。因为对局部进行处理往往比长远考虑要容易的多。而且在一定的问题中,“只顾眼前”反而能得到“长远最优”,此时使用贪心算法来求解就非常方便。
  • 换一句话讲,贪心算法就是把问题的求解分为好多步,在每一步内取当前的局部最优,并且最终能够通过这些局部的最优解达到全局最优。
    因为贪心算法无论是构造还是实现都非常简单,因此在解一道题时往往都会优先想到一个或者多个贪心算法。因为贪心算法的“简单”,导致其在比赛中频频出现,时不时给出题人或选手带来惊喜,并且也留下了许多传颂千古的名言警句。

正确性检验

  • 贪心算法的正确性,指的是一个贪心算法能否通过局部最优最终推得全局最优。贪心算法虽然在每一步只用考虑当前步骤,处理起来非常简单。然而,如果不证明正确性,我们就没法确定最终得到的解就是最优的。因此,在设计出一种贪心算法后,我们都需要证明其正确性。
    然而,贪心算法的正确性证明非常困难。而且针对不同的问题,证明方法多种多样。
  • 一种比较常用的证明思路为:
  • 用贪心算法得到的所有局部最优解构造一个解的序列/集合(根据题目的解是否有序)
  • 列举出其他所有可能的解的序列/集合
  • 证明所有其他序列/集合的解都不优于贪心算法得到的解

贪心算法的优缺点

  • 贪心算法的优势
    1.算法思想比较简洁、直观
    2.只用考虑局部情况,实现非常简单
    3.复杂度较优,效率较高
  • 贪心算法的劣势
    1.正确性证明非常困难
    2.证伪时的反例构造比较困难
    3.有些贪心题的结论很难想到

二、例题

1.Yogurt factory

参考文章:Poj 2393 Yogurt factory【贪心】

2.Regular Bracket Sequence

参考文章:A. Regular Bracket Sequence(思维)

3. 今年暑假不AC

参考文章:杭电-今年暑假不AC

4. Sasha and Magnetic Machines

参考文章:Codeforces 1113B. Sasha and Magnetic Machines 题解

5. Serval and Parenthesis Sequence

参考文章:C. Serval and Parenthesis Sequence(合法括号序列)

6. Crossing River

#include <iostream>
#include <algorithm>

using namespace std;
int cmp(int a,int b)
{
    return a<b;
}
int a[1010]= {};
int main()
{
    int T,n,t;
    int i;
    cin >> T;
    while(T--)
    {
        t = 0;
        cin >> n;
        for(i=0; i<n; i++)
        {
            cin >>a[i];
        }
        sort(a,a+n,cmp);
        if(n<=3)
        {
            if(n==1)t=a[0];
            if(n==2)t=a[1];
            if(n==3)t=a[2]+a[0]+a[1];
        }
        else
        {
            for(int i=n-1;i>0;i=i-2)
            {
                if(i>=3)
              {
                  if(a[0]+a[i-1]>=2*a[1])
                    t=t+a[0]+2*a[1]+a[i];
                  else
                    t=t+2*a[0]+a[i]+a[i-1];
              }
                if(i==2)
                    t=t+a[0]+a[1]+a[2];
                if(i==1)
                    t=t+a[1];

            }
        }
        cout << t << endl;
    }
    
    return 0;
}

参考文章:poj-1700 crossing river(贪心题)


总结

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

竹清兰香

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值