一.关于二分查找的学习及反思
1.要点
(1)二分查找法只适用于从有序的队列中进行查找(比如数字和字母等),将队列排序后再进行查找。
(2)首先将该组数据从中间划分为等长的两组(即便原数组不是偶数也没关系,取前面一半为一组,后面剩下的为一组即可)。
(3)与正中间的元素(一般是数组的长度除2并且向下取整)进行比较,如果想要查找的数据比当前被比较数据小,那么我们对左边的数组进行如上重复操作;如果想要查找的数据比当前数据大,同理,则对右侧的数组再次做第一步的操作;
(4)重复如上操作,直至想要查找的数据与当前被比较数据相同,这个时候算法结束。
2.几个易错点
(1)循环退出条件:
注意是low<=high,而不是 low
(2)mid 的取值:
实际上,mid=(low+high)/2 这种写法是有问题的。因为如果 low 和 high 比较大的话,两者之和就有可能会溢出。改进的方法是将 mid 的计算方式写成low+(high-low)/2。更进一步,如果要将性能优化到极致的话,我们可以将这里的除以 2 操作转化成位运算 low+((high-low)>>1)。因为相比除法运算来说,计算机处理位运算要快得多。
(3)low 和 high 的更新
low=mid+1,high=mid-1。注意这里的 +1 和 -1,如果直接写成 low=mid 或者 high=mid,就可能会发生死循环。比如,当 high=3,low=3 时,如果 a[3]不等于 value,就会导致一直循环不退出。
二.关于对贪心算法的学习及思考
1.贪心算法思想
顾名思义,贪心算法总是作出在当前看来最好的选择。也就是说贪心算法并不从整体最优考虑,它所作出的选择只是在某种意义上的局部最优选择。当然,希望贪心算法得到的最终结果也是整体最优的。虽然贪心算法不能对所有问题都得到整体最优解,但对许多问题它能产生整体最优解。如单源最短路经问题,最小生成树问题等。在一些情况下,即使贪心算法不能得到整体最优解,其最终结果却是最优解的很好近似。
2.贪心算法基本要素
(1)贪心选择性质。所谓贪心选择性质是指所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到。这是贪心算法可行的第一个基本要素,也是贪心算法与动态规划算法的主要区别。
动态规划算法通常以自底向上的方式解各子问题,而贪心算法则通常以自顶向下的方式进行,以迭代的方式作出相继的贪心选择,每作一次贪心选择就将所求问题简化为规模更小的子问题。
对于一个具体问题,要确定它是否具有贪心选择性质,必须证明每一步所作的贪心选择最终导致问题的整体最优解。
(2) 当一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质。问题的最优子结构性质是该问题可用动态规划算法或贪心算法求解的关键特征。
3.贪心算法的基本思路
从问题的某一个初始解出发逐步逼近给定的目标,以尽可能快的地求得更好的解。当达到算法中的某一步不能再继续前进时,算法停止。
该算法存在问题:
(1) 不能保证求得的最后解是最佳的;
(2)不能用来求最大或最小解问题;
(3) 只能求满足某些约束条件的可行解的范围。
实现该算法的过程:
从问题的某一初始解出发;
while 能朝给定总目标前进一步 do
求出可行解的一个解元素;
4,种树问题之贪心算法的运用
#include<stdio.h>//贪心算法
#include<algorithm>
using namespace std;
struct tree
{
int b,e,t;
}s[501000];
bool cmp(tree k,tree l)
{
return k.e<l.e;
}
int flag[501000];
int main()
{
int i,j,sum=0,n,h;
scanf("%d%d",&n,&h);
for(i=1;i<=h;i++)
scanf("%d%d%d",&s[i].b,&s[i].e,&s[i].t);
sort(s+1,s+h+1,cmp);// 按结束位置从小到大排序
for(i=1;i<=h;i++)//先循环遍历此路段是否满足建议需求
{
int z=0;
for(j=s[i].e;j>=s[i].b;j--)
{
if(flag[j]==1)//此处已有树
z++;
}
if(z>=s[i].t) continue;
for(j=s[i].e;j>=s[i].b;j--)//再循环从右端点开始种树
{
if(flag[j]==0)//说明 此条建议已被满足
{
flag[j]=1;//种上树
z++;
sum++;
}
if(z==s[i].t) break;
}
}
printf("%d\n",sum);
return 0;
}