c语言贪心算法过河,算法总结之贪心算法

算法总结之贪心算法

贪心算法概要

贪心算法,顾名思义,就是做出对当前最有利的选择。贪心算法并不从整体最优考虑,而是一定意义上的局部最优解。当然在很多情况下,贪心算法得到的最优解也是整体上的最优解,如最短路径问题、最小生成树问题,一些情况下,贪心算法得到的即使不是全局最优解,其结果也是最优解的很好近似。当问题的精确求解变得非常困难时,使用贪心算法对问题进行求解,也是一种可行的办法。

但是需要注意的是贪心算法进行求解的问题是有条件的,只能对特定类型的问题使用,也就是组合优化问题。组合优化问题首先考虑的是这个问题能不能正面解决,也就是看它能否进行规约,将其变为一个个小问题。然后根据我们学过的知识,判断能不能进行分治法求解,继续观察原问题的结构,如果问题能够问题能继续分解为最优子结构,就意味着我们可以使用动态规划进行求解,这也是我们之前学过的分治法和动态规划的求解思路。在这两个求解思路上,如果问题不仅仅可以被规约成小的问题,并且它有最优子结构性质,同时还具备第三种性质:贪心选择,那此时可以采取第三种方法,贪心算法来进行问题的求解。

贪心算法的基本思路:给定一个初始的解出发慢慢逼近给定的目标,直至问题中的条件得到满足无法继续进行求解,显然选定的初始条件会对问题的求解精度产生很大的影响。

下面对一些常见的贪心算法的问题做一些总结归纳。

课程安排问题

这是教科书上典型的贪心算法,延伸出来的活动安排等问题也是一样的。有N个课程集和一间教室,教室同时只能被一个课程占用,每个课程有开始时间s i s_isi​和结束时间f i f_ifi​,现要求尽可能多的使参加的活动最大化,也就是所占时间区间的最大化。

这道问题的贪心策略就是按照结束时间对所有课程排序,选择结束时间尽量早的课程,然后选择的下一个课程开始时间晚于当前课程的结束时间。算法得到的解为全局最优解,贪心选择的意义使剩余的可安排时间最大化,从而安排最多的相容活动。

具体代码为

//输入数组s、j为排好序的课程开始和结束数组,A为标记选择哪个课程的数组,初始化为0

void greedySelector(int n, vector& s, vector& f, vector& A){

A[1] = true;

int j = 1; //最近一次加入的活动

for(int i=2; i=f[j]){

A[i] = true;

j = i;

}

}

}

算法的时间复杂度与排序的时间复杂度相同,为O ( n l o g n ) O(nlogn)O(nlogn)。

乘船渡河

一群人乘船渡河,单个人的体重不会超过穿的载重,每条船最多载两人并且不能超出船的载重,求最少需要多少条穿才能让所有人都过河。

贪心策略为让体重大的人尽量和体重小的人凑对坐船

正确性证明:ABCD四个人是按照体重从大到小排序的,P A > P B > P C > P D P_A>P_B>P_C>P_DPA​>PB​>PC​>PD​,若不按照贪心策略,安排B和D坐一条船,此时A和C可能坐一条船,也可能坐不下;

若A和C可以坐一条船,那么四个人需要两条,分别为(A,C)和(B,D)。既然(A,C)可以,那么(A,D),(B,D)组合同样满足,此时贪心策略也是需要两条船。

若A和C不能坐上同一条船,那么四个人需要三条船才能满足条件,分别为A,C,(B,D),按照贪心策略,尽量保证(A,D)和(B,C)的匹配,若A、D能坐一条船,如果B、C能坐一条船,此时需要两条船,否则需要三条船。若A、D不能做一条船,那么A一条船,B、C一条船,D一条船,此时需要三条船

因此贪心策略的算法总是会产生最小的坐船数量。

具体代码为:

int minBoat(vectorweight, int limit){

int n = weight.size();

sort(weight.begin(), weight.end());

int l = 0, r = n-1;

int result = 0;

while(l <= r){

if(weight[r] >= limit || weight[r] + weight[l] >= limit){

r--;

result++;

}

else{

l++;

r--;

result++;

}

}

return result;

}

算法的时间复杂度与排序的时间复杂度相同,为O ( n l o g n ) O(nlogn)O(nlogn)。

绳子乘积最大

将绳子剪为不定长不定数量的小段,使得所有数量的小段绳子乘积最大。

贪心策略为尽量裁剪长度为3的小段绳子。

正确性证明:当绳子长度小于5时,不用裁剪;数量继续增长,总能分解为2的累加,对于绳子拆分为2的累加情况,由于2 ∗ 2 ∗ 2 < 3 ∗ 3 2*2*2<3*32∗2∗2<3∗3,因此将绳子拆分为3的小段所得乘积最大

算法代码为:

int maxRope(int len){

if(len < 5) return len;

int times3 = len%3 == 1? len/3-1: len/3;

int remainder3 = len - 3*times3;

return pow(3, times3)*remainder3;

}

计算时间复杂度为幂的计算时间复杂度,为O ( l o g n ) O(logn)O(logn)。

猴子香蕉问题

一条直线上有N个位置,每个位置要么是猴子,要么是香蕉。每只猴子只能吃一根香蕉,猴子可以吃到离它左右两边最远K步远的香蕉,求被猴子吃掉的最多香蕉数。

贪心策略为猴子吃掉从左边第K步远到右边K步远的第一根香蕉

贪心策略的证明:第X个猴子吃X左边第K步远到右边K步远的第一根香蕉A,如果不吃,那么后面的猴子很有可能吃不到这根香蕉,并且后面的猴子可能没有香蕉吃,那么吃掉的香蕉数量肯定比贪心策略得到的数量小。

具体的代码为:

int maxBanana(vectorline, int K){

int n = line.size();

int result = 0;

for(int i=0;in-1) continue;

if(line[j] == 'B'){

result++;

line[j] = "S";

break;

}

}

}

}

return result;

}

遍历整个数组,算法的时间复杂度为O ( n ) O(n)O(n)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值