【算法笔记】4.4 贪心

  • 这是《算法笔记》的读书记录
  • 本文参考自4.4节

1. 简单贪心

  • 贪心法是求解一类最优化问题的方法他,它总是考虑当前状态下的局部最优的策略,来使全局结果达到最优
  • 不是所有问题都能用贪心法解决,因此要严谨地使用贪心算法,需要对策略进行证明。证明的一般思路是使用反证法及数学归纳法,先假设策略不能达到最优,然后根据一系列推到得出矛盾,从而证明策略是最优的,最后通过数学归纳法保证全局最优
  • 真正做题的时候,往往没有时间严谨证明(给出一个严谨的证明往往比写出算法本身更难)。所以一般只要想到贪心似乎可行,且举不出反例,就可以用贪心做一下试试
  • 示例:
    1. PAT乙级 —— 1010 月饼 (25)
    2. PAT乙级 —— 1013 组个最小数 (20)

2. 区间贪心

(1)区间不相交问题

  • 来看一个稍微复杂一点的问题,现有多个开区间,要从中找出尽量多的区间,使得找出部分两两互不相交

  • 先考虑最简单的情况,如下图,I1被I2包含,这时应该选I1,给其他区间留出更大的空间
    在这里插入图片描述

  • 现在假设通过上述方法去除了所有发生包含的区间,把剩下的区间按左端点从大到小排序,从上往下画如下。 这样每一个区间,都可以被它相邻那个的右端点分成两段(如I1被I2右端点分成两段),其中右边部分是不和任何区间重合的,左边部分和相邻区间又组成了上面简单情况的关系,因此应该选上面的那个区间(I1)
    在这里插入图片描述

  • 现在考察一个一般情况,这里没有去除发生包含的区间,先按左端点从大到小排序,再按右端点从小到大排序,从上往下画如下。根据上面的分析,这里应该选E1,E2
    在这里插入图片描述

  • 总结一下,总是选择左端点最大的区间(当左端点相同时选右端点最小的),依次往后找出所有不相交的区间即可

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    
    struct Inteval
    {
          
          
    	int x,y;	//左右端点 
    }I[110];
    
    bool cmp(Inteval a,Inteval b)
    {
          
          
    	if(a.x!=b.x)
    		return a.x>b.x;	//左端点大到小
    	return a.y<b.y;		//右端点小到大 
    } 
    
    int main()
    {
          
          
    	int n;						//区间个数 
    	while(scanf("%d",&n),n!=0)
    	{
          
          
    		for(int i=0;i<n;i++)
    			scanf("%d%d",&I[i].x,&I[i].y);
    		
    		sort(I,I+n,cmp);
    		
    		int ans = 1;			//不相交区间计数 
    		int lastX = I[0].x;		//记录上一个区间左端点 
    		
    		for(int i=1;i<n;i++)
    		{
          
          
    			if(I[i].y<=lastX)
    			{
          
          
    				lastX = I[i].x;
    				ans++;
    			}	
    		}	
    		
    		printf("%d",ans);
    	} 
    	
    	return 0;
    }
    

(2)区间选点问题

  • 区间选点问题和区间不相交问题类似:给定若干区间,问至少要几个点,才能使每个区间中都至少存在一个点
  • 先考虑最简单的情况,如下图,I1被I2包含,这时应在I1中选一个点
    在这里插入图片描述
  • 现在假设通过上述方法去除了所有发生包含的区间,把剩下的区间按左端点从大到小排序,从上往下画如下。现在对于I1来说,选哪个点可以尽量多地覆盖其他区间?显然是左端点。
    在这里插入图片描述
  • 事实上,这个问题和区间不相交问题的代码也几乎完全一致,只要把if(I[i].y<=lastX)改成if(I[i].y<lastX)就行了。我们只要仿照上面的方法找出所有不相交区间,可以保证其他区间总有一部分和找出的区间重合,所以在每个找出的区间上放一个点就行了,只不过这里不能出现两个区间公用端点的情况

3. 小结

  • 总的来说,贪心是用来解决一类最优化问题,并希望由局部最优解来推全局最优解的算法思想。
  • 贪心算法适用的问题一定满足最优子结构性质:即一个问题的最优解可以由其子问题的最优解有效构建出来
  • 不是所有问题都适用与贪心算法

猜你喜欢

转载自blog.csdn.net/wxc971231/article/details/108463912