算法第四章作业
一、贪心算法
贪心算法通过一系列的选择来得到问题的的解。它所做的每一个选择都是当前状态下局部最好选择,即贪心选择。
贪心算法一般具有两个重要的性质。
1.贪心选择性质:贪心选择性质是指所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择。
在动态规划算法中,每步所做的选择往往依赖于相关子问题的解。
贪心算法所做的贪心选择可以依赖于以往所做过的选择,但决不依赖于将来所做的选择,也不依赖于子问题的解。
动态规划算法通常以自底向上的方式解各个子问题,而贪心算法则通常以自顶向上的方式进行,以迭代的方式做出相继的贪心选择,每做一次贪心选择就将所求问题简化为规模更小的子问题。
对于一个具体问题,要确定它是否具有贪心选择性质,必须证明每一步所做的贪心选择最终导致问题的整体最优解。
2.最优子结构性质
当一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构的性质。问题的最优子结构性质是该问题可用动态规划或贪心算法求解的关键特征。
二、汽车加油问题
1.问题描述
一辆汽车加满油后可行驶n公里。旅途中有若干个加油站。设计一个有效算法,指出应在哪些加油站停靠加油,使沿途加油次数最少。
2.解题思想:汽车走到离每次出发点最远的加油站,到了最远的加油站后再按照同样的方法贪心。
3.题解
(1)先检测各加油站之间的举例,若发现其中有一个距离大于汽车加满油能跑的举例,则输出“No Solution!”。
(2)否则,对加油站间的距离进行逐个扫描,并且累加记录举例,尽量选择往远处走,不能走了,即当累加举例大于n时,就加油一次(count++), 最终统计出来的count就是最少的加油站数。
(3)代码如下:
#include <stdio.h>
int main() {
int n, k; scanf("%d %d", &n, &k);
int a[1005];
for (int i = 0; i <= n; i++) {
scanf("%d", &a[i]);
}
int sum = 0, count = 0, flag = 0;
a[k+1] = 0;
for (int j = 0; j <= k; j++) {
sum += a[j];
if (n - sum <= a[j+1] && n >= a[j]) {
sum = 0;
count++;
}
if (n < a[j])
flag = 1;
}
if (flag == 0)
printf("%d\n", count);
else
printf("No Solution!\n");
return 0;
}
4.算法复杂度分析
(1)该算法只需要对于加油站数组进行扫描,故时间复杂度为O(n)。
(2)该算法的空间复杂度为O(1)。
三、学习过程及结对编程
1.问题
(1)什么是贪心算法?
答:如上所述。
(2)贪心算法与动态规划算法的区别是什么?
答:动态规划通常以自底向上(求解子问题)的方式解各子问题,而贪心算法则通常以自顶向上(贪心局部,但不是子问题)的方式进行,以迭代的方式做出相继的贪心选择,每做一次贪心选择就将所求问题简化为规模更小的子问题。
(3)对于具有最优子结构的问题应该选用贪心算法还是动态规划算法来求解?
答:贪心法:一意孤行;动态规划:三思而后行。实际上,贪心算法与动态规划算法都要求问题具有最优子结构性质。对于具有大量重叠子问题的问题,应采用动态规划算法;对于需要做出贪心选择的问题,采用贪心算法。
2.结对编程情况:先自己独立完成 -> (已完成/未完成)与partner交流思想(未完成partner帮忙查验代码) -> 独立完成
四、参考资料
1.课本《计算机算法分析与设计》
2.https://blog.csdn.net/ii1245712564/article/details/45420061#1-3贪心算法vs动态规划