贪心算法的定义:
贪心算法是指在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,只做出在某种意义上的局部最优解。贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。
解题的一般步骤是:
1.建立数学模型来描述问题;
2.把求解的问题分成若干个子问题;
3.对每一子问题求解,得到子问题的局部最优解;
4.把子问题的局部最优解合成原来问题的一个解。
例题1:区间选点
题目链接:905. 区间选点 - AcWing题库
不在活动内可能提交不了代码,也看不了题目,这里把题面切图出来,主要讲一下思路,和为什么能用贪心来写。
题面:
思路
1)将每个区间按右端点从小到大进行排序
2)从前往后一次枚举每个区间
如果当前区间中已经有包含点,这直接pass
否则,选择当前区间的右端点
如下:选第一个区间的右端点,第二、三个区间也包含此点。
选第四个区间的右端点,第五个区间也包含此点。
由此可见只需要两个点。
看似取得是每一步的最优取法,其实是可以证明此取法就是总体最优解。
假设答案就是ans,我们算出的取法是cnt。
想一下要证明cnt就是等于ans的,可以先证明ans<=cnt,在证明ans>=cnt,就能推出ans=cnt了。
(1)由于ans是所需的点的最小数量,cnt是依次枚举每个区间选出来的点数,肯定ans<=cnt
(2)如果当前区间包含了此点,则不在此区间选点。若区间不包含此点,则选此区间的右端点。
每个区间都是2)中否则的情况。也就是我们找到了cnt个区间之间没有任何交集的情况,此时ans>=cnt
由此可以推出:cnt=ans。
代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef long long ll;
const int N=1e5+10;
struct range
{
int l,r;
}a[N];
bool cmp(struct range&x,struct range&y)
{
return x.r<y.r;//右端点按从小到大顺序排序
}
signed main()
{
int n;
cin>>n;
for(int i=0;i<n;i++)
cin>>a[i].l>>a[i].r;
sort(a,a+n,cmp);//每个区间按右端点排序
int ans=0,ed=-2e9;//最开始右端点初始值赋值为负无穷
for(int i=0;i<n;i++)
{
if(a[i].l>ed)
{
ans++;
ed=a[i].r;
}
}
cout<<ans<<endl;
return 0;
}