【无标题】

贪心算法

概念:把整个问题分为多个步骤,在每个步骤都选取当前步骤的最优方案,直到这个步骤结束,每一步都不考虑对后续步骤的影响,在后续步骤中不再改变前面的选择。

例题:最少硬币问题

题目描述:某人带着3种面值的硬币去购物,有1元、2元、5元的,硬币数量不限;他需要支付M元,问怎么支付,才能使硬币数量最少?

第一步应该先拿出面值最大的 5 元硬币,第二步拿出面值第二大的 2 元硬币,最后才拿出面值最小的 1 元硬币。在这个解决方案中,硬币数量总数是最少的

#include<bits/stdc++.h>
using namespace std;
const int n = 3;
int coin[] = {1,2,5};
int main(){
    int i, money;
    int ans[n] = {0};               //记录每种硬币的数量
    cin >> money;                   //输入钱数
    for(i= n-1; i>=0; i--){         //求每种硬币的数量
        ans[i] = money/coin[i];
        money = money - ans[i]*coin[i];
    }
    for(i= n-1; i>=0; i--)
        cout << coin[i]<<": "<<ans[i]<<endl; //输出每种面值硬币的数量
    return 0;
}

能使用贪心法求解的问题,需要满足以下特征:

  1. 最优子结构性质。当一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质,也称此问题满足最优性原理。也就是说,从局部最优能扩展到全局最优。
  2. 贪心选择性质。问题的整体最优解可以通过一系列局部最优的选择来得到。
贪心算法的几个题型:
1.区间调度问题:

题目描述:有很多电视节目,给出它们的起止时间。有的节目时间冲突。问能完整看完的电视节目最多有多少?

输入:输入数据包含多个测试实例,每个测试实例的第一行只有一个整数 n*(*n<=100),表示节目总数,然后是 n 行数据,每行包括两个数据 s, e,分别表示第 i个节目的开始和结束时间,为了简化问题,每个时间都用一个正整数表示。n=0表示输入结束,不做处理。

输出:对于每个测试实例,输出能完整看到的电视节目的个数,每个测试实例的输出占一行。

这里可以想到三种贪心策略

1.最早开始时间

2.最早结束时间

3.用时最少

第 2种策略是合理的,尽快终止一个活动,可以容纳更多的后续活动。

下面的图是例子,最优活动是 1、3、5,活动 2、4 与其它节目有冲突。

  1. 为什么它对呢
  2. 它符合最优子结构性质。选中的第 1个活动,它一定在某个最优解中;同理,选中的第 2 个活动、第 3 个活动……也同样在这个最优解中。

  3. 它符合贪心选择性质。算法的每一步都使用了相同的贪心策略

#include<bits/stdc++.h>
using namespace std;
#define MAXN 100
struct record {
    int s, e;    //定义活动的起止时间: start, end
} r[MAXN];
bool cmp(const record& a, const record& b)
{ return a.e < b.e;  }
int main(){
    int n;
     while(1){
        cin >> n;    //输入n个活动
        if(n == 0)   break;  // n==0时结束
        for(int i=0; i<n; i++)  //输入每个活动的起止时间
            cin >> r[i].s >> r[i].e;
        sort(r, r + n, cmp);  // 排序:按结束时间排序
        int count = 0;         //统计活动个数
        int lastend = -1;
        for(int i=0; i<n; i++) // 贪心算法
            if(r[i].s >= lastend) {//后一个起始时间 >= 前一个终止时间
                count++;
                lastend = r[i].e; //记录前一个活动终止时间
            }
        cout << count << endl; //输出活动个数
    }
    return 0;
}
区间覆盖问题

题目描述:给定一个长度为 n 的区间,再给出 m 条线段的左端点(起点)和右端点(终点)。问最少用多少条线段可以将整个区间完全覆盖

  1. 把每个线段按照左端点递增排序。
  2. 设已经覆盖的区间是 [L, R][L,R] ,在剩下的线段中,找所有左端点小于等于 R,且右端点最大的线段,把这个线段加入到已覆盖区间里,并更新已覆盖区间的 [L, R][L,R] 值。
  3. 重复步骤 2,直到区间全部覆盖。

图片描述

图2 区间覆盖

大佬:图 2 中,所有线段已按左端点进行排序。于是首先选中线段 1,然后在 2 和 3 中,选中更长的 3 。而 4 和 5 由于不合要求,被跳过。最后的最优解是 1、3。

最优装载问题(普通背包问题)

题目描述:有 n 种药水,体积都是 V ,浓度不同。把它们混合起来,得到浓度不大于 w% 的药水。问怎么混合,才能得到最大体积的药水?注意一种药水要么全用,要么都不用,不能只取一部分。

解题思路:先对药水按浓度从小到大排序,药水的浓度不大于 w% 就加入,如果药水的浓度大于 w%,计算混合后总浓度,不大于 w% 就加入,否则结束判断。

多机调度问题

题目描述:设有 n 个独立的作业,由 m 台相同的机器进行加工。作业 i 的处理时间为 ti,每个作业可在任何一台机器上加工处理,但不能间断、拆分。要求给出一种作业调度方案,在尽可能短的时间内,由 m 台机器加工处理完成这 n 个作业。

求解多机调度问题的贪心策略是:最长处理时间的作业优先,即把处理时间最长的作业分配给最先空闲的机器。让处理时间长的作业得到优先处理,从而在整体上获得尽可能短的处理时间。

  1. 如果 n<=m,需要的时间就是 n 个作业当中最长处理时间 t
  2. 如果 n>m,首先将 n 个作业按处理时间从大到小排序,然后按顺序把作业分配给空闲的机器。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值