一、贪心算法的特点:
1、贪心选择:
所谓贪心选择是指应用同一规则,将原问题变为一个相似的但规模更小的子问题,而后的每一步都是当前看似最佳的选择,且这种选择只依赖于已做出的选择,不依赖未做出的选择。
2、最优子结构:
执行算法时,每一次得到的结果虽然都是当前问题的最优解(即局部最优解),但只有满足全局最优解包含局部最优解是,才能保证最终得到的结果是最优解。
二、几个贪心例子:
1、最优装载问题
给n个物品,第i个物品重量为wi,选择尽量多的物品,使得总重量不超过C。
【思路】
由于只关心物品的数量,所以装重的没有装轻的划算,只需把所有物品按重量从小到大排序,以此选择每个物品,知道装不下为止。它只顾眼前,却能得到全局最优解。
2、部分背包问题
有n个物品,第i个物品的重量为wi,价值为vi,在总重量不超过C的情况下,让总价值尽量高,每一个物品可以只取走一部分,价值和重量按比例计算。
【思路】
贪心策略:先选出性价比最高的。
注意:由于每个物品可以只选出一部分,因此一定可以让总重量恰好为C(或者所有物品全选,总重量还不足C),而且除了最后一个以外,所有物品要么不选,要么全部选。
3、乘船问题
有n个人,第i个人重量为wi。每艘船的载重量均为C,最多可乘两个人。求用最少的船装在所有人的方案。
【思路】
贪心策略:最轻的人和最重的人配对。
程序实现:我们只需用两个指针i和j分别表示当前考虑的最轻的人和最重的人。每次先将指针j往左移动,直到i和j可以共乘一艘船,然后将指针i往右移,指针j往左移动。
三、贪心算法的经典应用
1、选择不相交区间问题
给定n个开区间(ai,bi),选择尽量多个区间,使得这些区间两两没有公共点。
【思路】
首先,按照结束时间 b1 <= b2 …… <= bn 的顺序排序,依次考虑各个活动,如果没有和已经选择的活动冲突,就选,否则就不选。
【正确性】
假设 bj < bi 且(aj,bj) 、(ai,bi) 分别与之前的活动不冲突,当前选(aj,bj),若(aj,bj)与(ai,bi)不冲突,则还可以选择(ai,bi),答案个数加一,若(aj,bj)与(ai,bi) 冲突,因为 bj < bi ,所以 (aj,bj)对以后的影响更小。
【例题】:活动安排
题目链接:传送门
题目描述
输入
接下来的n行,每行两个整数si和fi。
输出
样例输入
4
1 3
4 6
2 5
1 7
样例输出
2
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N = 10005; 4 typedef struct Node { 5 int S,F; 6 }Node ; 7 Node a[N]; 8 bool cmp ( Node u , Node v ){ 9 if( u.F == v.F ){ 10 return u.S < v.S ; 11 } 12 return u.F < v.F ; 13 } 14 int n ; 15 int main () { 16 scanf("%d",&n); 17 for ( int i = 0 ; i < n ; i++ ){ 18 scanf("%d%d",&a[i].S, &a[i].F ); 19 } 20 sort ( a , a+n ,cmp ); 21 int ans = 1 ; 22 int F = a[0].F; 23 for ( int i = 1 ; i < n ; i++ ){ 24 if( F <= a[i].S ){ 25 F = a[i].F ; 26 ans ++ ; 27 } 28 } 29 printf("%d\n",ans ); 30 return 0; 31 }