贪心算法
贪心的定义
-贪心搜索算法是一种在每一步选择中都采取当前状态下最优的选择,以达到整体的局部最优解。它不保证最终结果是最佳的全局解,但在某些情况下提供了一种快速且实用的解决方案。贪心算法在解决最短路径问题等方面应用广泛,尤其是在图和树的搜索中表现出高效的性能。
比如,你面前有一堆不同面额的硬币(比如 1 元、5 角、1 角),你需要用最少数量的硬币凑出 1.8 元。一个很自然的想法是:每次都先拿面额最大的硬币。先拿 1 元,剩下 0.8 元;再拿 5 角,剩下 0.3 元;最后拿三个 1 角。整个过程,我们在每一步都做出了 当前看来最好的选择,这就是贪心算法的核心思想。
贪心算法就像是一个目光短浅但决策果断的人:
·每一步选择:在当前状态下做出看起来最优的选择
·不考虑全局:不考虑这个选择对未来的影响
·期望结果:希望局部最优选择能导致全局最优解
现实中的案例:
·找零钱:总是先用最大面额的硬币
·爬山:总是朝最陡峭的方向前进
·购物:总是买当前最优惠的商品
·路线选择:总是选择当前最短的路
贪心算法的特点
·贪心选择性质:每一步的最优解,都可以由之前各步的局部最优解推导出来。后面的选择不会影响之前的选择。
·最优子结构:一个问题的最优解包含其子问题的最优解。这是动态规划也具有的性质,但贪心算法在每一步都”贪心地”选择子问题的最优解。

与动态规划的区别

贪心算法的基本框架
#include<bits/stdc++.h>using namespace std;int main(){//1、初始化:包括排序、创建结果容器等//2、遍历所有可选项,通常需要先按某种规则排序//3、贪心选择:如果当前选择满足条件,就采纳它//4、返回最终构造的解return 0;}
经典问题与代码示例
1、平均分配问题
【问题描述】 有 N 堆苹果,编号分别为 1,2,…, N。每堆上有若干个,但苹果总数必为 N 的倍数。可以在任一堆上取若干个苹果,然后移动。移苹果规则为:在编号为 1 堆上取的苹果,只能移到编号为 2 的堆上;在编号为 N 的堆上取的苹果,只能移到编号为 N-1 的堆上;其他堆上取的苹果,可以移到相邻左边或右边的堆上。现在要求找出一种移动方法,用最少的移动次数使每堆上苹果数都一样多。
输入:N(N 堆苹果,1 <= N <= 100)A1 A2 … An (N堆苹果,每堆苹果初始数,1<= Ai<=10000) 输出:所有堆均达到相等时的最少移动次数。
代码如下:
#include<bits/stdc++.h>using namespace std;int p[1005];int main(){int n,i;cin>>n;int f=0, c=0;for( i=0;i<n;i++){cin>>p[i];f+=p[i];}f/=n;for(i=0;i<n-1;i++){if(p[i] != f){p[i+1]=p[i+1]-(f-p[i]);c++;}}cout<< c;return 0;}
2、找零钱
【问题描述】 悟空和八戒在集市买苹果,现需要找给客户N元零钱。假设有数目不限,面值为20,10,5,1的硬币。如何使得找出的硬币数量最少?
输入:一个正整数n,表示需要找的零钱数目。(0<n<100)
输出:找出的最少零钱数目。
代码如下:
#include<bits/stdc++.h>using namespace std;int main(){int n;cin>>n;int count = 0;int coins[] = {20,10,5,1};for(int i = 0;i < 4 ;i++){count += n/coins[i];n = n % coins[i];}cout<<count;return 0;}
3、活动选择
题目描述
学校在最近几天有n个活动,这些活动都需要使用学校的大礼堂,在同一时间,礼堂只能被一个活动使用。由于有些活动时间上有冲突,学校办公室人员只好让一些活动放弃使用礼堂而使用其他教室。
现在给出n个活动使用礼堂的起始时间begin_i和结束时间end_i(begin_i < end_i),请你帮助办公室人员安排一些活动来使用礼堂,要求安排的活动尽量多。
代码如下:
#include<bits/stdc++.h>using namespace std;struct JGT{int s;int t;}a[1005];int n;bool cmp(JGT x,JGT y){return x.t<y.t;}int cnt = 0;int main(){cin>>n;for(int i=0;i<n;i++){cin>>a[i].s>>a[i].t;}sort(a+1,a+1+n,cmp);int m = 0;for(int i=1;i<=n;i++){if(a[i].s>=m){cnt++;m=a[i].t;}}cout<<cnt;return 0;}
4、额外的报酬
题目描述
假设本月新收若干个不同订单,其难易程度为一级、二级、三级…同样,能够完成不同难度订单的工人也被分为若干星级,并且x星级的工人能够完成x级别以下的所有任务。
现有m个订单,n个空闲工人,请问能否完成所有订单呢?如果可以,最少的花费是多少呢?
注:每个工人当月只能完成一件任务。
输入: 第一行两个整数m和n,分别表示订单量和工人量。 (1<=n,m<=20000)
第二行m个整数,表示每个订单的难易级别;
第三行n个整数,表示每个工人的星级。
输出:如果可以完成:第一行输出最小花费,接下来m行每行两个整数,分别表示订单级别与相应的工人级别(用空格隔开)。否则,直接输出“Failed”。
5、八戒的礼物
题目描述
八戒购买了若干件礼物,想要以“价值相对均衡”为前提,将礼物进行分组,并且保证每组礼物件数不超过两件,同时保证每组的礼物价值总和不能超过一个给定的整数。为了保证在尽量短的时间内发完所有礼物,八戒要使分组数最少,你知道他是如何完成的吗?
输入:第一行两个整数max和n,分别表示每组礼物的价值上限、礼物总件数;(1<=n<=30000,10<=max<=1000)
第二行有n的整数x,分别表示n件礼物的价值。(5<=x<=max)
输出:一个整数,表示最少的分组数目。
代码如下:
#include<bits/stdc++.h>using namespace std;const int Max = 100000;int main(){int max,n;cin>>max>>n;int p[Max];for(int i=0;i<n;i++){cin>>p[i];}sort(p,p+n);int r = n - 1, l = 0;int count = 0;while(l <= r){if(p[l]+p[r] <= max){l++;}r--;count++;}cout<<count<<endl;return 0;}
